Summary
docs/examples/applied_freeze.py produces zero rows on current develop (b5e4df5).
Every FourCastNetv2 case is rejected by the pre-flight check and the run finishes in
about 6 seconds with an empty CSV.
WARNING Data input FourCastNetv2 for case 30 has no data for case time range 2021-02-10 12:00:00 to 2021-02-22 00:00:00.
WARNING Data input FourCastNetv2 for case 31 has no data for case time range 2022-02-17 18:00:00 to 2022-03-01 06:00:00.
elapsed: 6.5s
wrote dev_freeze.csv rows=0
The data is present. The check is wrong.
Cause
sources.xarray_dataset.check_for_valid_times tries valid_time, time, then
init_time, and depends on .sel raising KeyError to move past a coordinate that
has no index:
for time_dim in ["valid_time", "time", "init_time"]:
if time_dim in data.coords:
try:
time_slice = data[time_dim].sel({time_dim: slice(start_ts, end_ts)})
return len(time_slice) > 0
except (KeyError, ValueError):
continue
FourCastNetv2 exposes valid_time as a non-indexed coordinate along lead_time, so
the first iteration decides the result. xarray changed what that call does:
xarray 2025.12.0 -> raises KeyError: "no index found for coordinate 'valid_time'"
xarray 2026.7.0 -> returns length 0, no exception
On 2026.7.0 the function returns False on the first iteration and never reaches
init_time, which is indexed and does cover the case range.
develop pins xarray 2026.7.0 after the dependency refresh in #386, so the example
broke with that upgrade rather than with any change to this function.
Minimal reproduction
import numpy as np, pandas as pd, xarray as xr
lead = pd.to_timedelta(np.arange(0, 4) * 6, unit="h")
init = pd.date_range("2020-09-30T12", periods=3, freq="12h")
ds = xr.Dataset(
{"t2": (["init_time", "lead_time"], np.zeros((3, 4)))},
coords={
"init_time": init,
"lead_time": lead,
"valid_time": ("lead_time", init[0] + lead),
},
)
assert "valid_time" not in ds.xindexes
ds["valid_time"].sel(valid_time=slice(pd.Timestamp("2021-02-10"), pd.Timestamp("2021-02-22")))
On 2025.12.0 this raises KeyError. On 2026.7.0 it returns an empty array.
Scope
Affects any input whose coordinates include a valid_time (or time) without an
index, since that coordinate is tried first and now returns empty instead of raising.
defaults.cira_fcnv2_freeze_forecast: valid_time present, not indexed. Affected.
- HRES in
applied_heatwave.py: no valid_time coordinate, so init_time is tried
first and is indexed. Not affected, and that example still returns 668 rows.
Suggested fix
Skip coordinates that have no index rather than relying on the exception, and keep
looking instead of returning on the first candidate that yields nothing:
for time_dim in ["valid_time", "time", "init_time"]:
if time_dim in data.coords and time_dim in data.xindexes:
if len(data[time_dim].sel({time_dim: slice(start_ts, end_ts)})) > 0:
return True
return False
Returning on the first non-empty match rather than on the first candidate also avoids
a related problem: a dataset with both an indexed valid_time covering nothing and an
indexed init_time covering the case would currently be rejected.
Needs a regression test with a non-indexed valid_time coordinate, which would have
caught this at the version bump.
Note
PR #387 appears to fix this, but only because its lockfile predates #386 and still
resolves xarray 2025.12.0. Rebasing it onto develop will reintroduce the failure.
Summary
docs/examples/applied_freeze.pyproduces zero rows on currentdevelop(b5e4df5).Every FourCastNetv2 case is rejected by the pre-flight check and the run finishes in
about 6 seconds with an empty CSV.
The data is present. The check is wrong.
Cause
sources.xarray_dataset.check_for_valid_timestriesvalid_time,time, theninit_time, and depends on.selraisingKeyErrorto move past a coordinate thathas no index:
FourCastNetv2 exposes
valid_timeas a non-indexed coordinate alonglead_time, sothe first iteration decides the result. xarray changed what that call does:
On 2026.7.0 the function returns
Falseon the first iteration and never reachesinit_time, which is indexed and does cover the case range.developpins xarray 2026.7.0 after the dependency refresh in #386, so the examplebroke with that upgrade rather than with any change to this function.
Minimal reproduction
On 2025.12.0 this raises
KeyError. On 2026.7.0 it returns an empty array.Scope
Affects any input whose coordinates include a
valid_time(ortime) without anindex, since that coordinate is tried first and now returns empty instead of raising.
defaults.cira_fcnv2_freeze_forecast:valid_timepresent, not indexed. Affected.applied_heatwave.py: novalid_timecoordinate, soinit_timeis triedfirst and is indexed. Not affected, and that example still returns 668 rows.
Suggested fix
Skip coordinates that have no index rather than relying on the exception, and keep
looking instead of returning on the first candidate that yields nothing:
Returning on the first non-empty match rather than on the first candidate also avoids
a related problem: a dataset with both an indexed
valid_timecovering nothing and anindexed
init_timecovering the case would currently be rejected.Needs a regression test with a non-indexed
valid_timecoordinate, which would havecaught this at the version bump.
Note
PR #387 appears to fix this, but only because its lockfile predates #386 and still
resolves xarray 2025.12.0. Rebasing it onto
developwill reintroduce the failure.