Description
The error message suggest that this is due to int64
values not fitting into int32
, even when this is not case.
To reproduce:
import xarray
import pandas as pd
# `lead_time` has a dtype of timedelta64[s]
xarray.Dataset({'lead_time': pd.timedelta_range('0h', '12h', freq='h', unit='s')}).to_netcdf()
This raises the following misleading error:
ValueError: could not safely cast array from int64 to int32. While it is not always the case, a common reason for this is that xarray has deemed it safest to encode np.datetime64[ns] or np.timedelta64[ns] values with int64 values representing units of 'nanoseconds'. This is either due to the fact that the times are known to require nanosecond precision for an accurate round trip, or that the times are unknown prior to writing due to being contained in a chunked array. Ways to work around this are either to use a backend that supports writing int64 values, or to manually specify the encoding['units'] and encoding['dtype'] (e.g. 'seconds since 1970-01-01' and np.dtype('int32')) on the time variable(s) such that the times can be serialized in a netCDF3 file (note that depending on the situation, however, this latter option may result in an inaccurate round trip).
Traceback:
[/usr/local/lib/python3.11/dist-packages/xarray/core/dataset.py](https://localhost:8080/#) in to_netcdf(self, path, mode, format, group, engine, encoding, unlimited_dims, compute, invalid_netcdf, auto_complex)
2028 from xarray.backends.api import to_netcdf
2029
-> 2030 return to_netcdf( # type: ignore[return-value] # mypy cannot resolve the overloads:(
2031 self,
2032 path,
[/usr/local/lib/python3.11/dist-packages/xarray/backends/api.py](https://localhost:8080/#) in to_netcdf(dataset, path_or_file, mode, format, group, engine, encoding, unlimited_dims, compute, multifile, invalid_netcdf, auto_complex)
1926 # TODO: allow this work (setting up the file for writing array data)
1927 # to be parallelized with dask
-> 1928 dump_to_store(
1929 dataset, store, writer, encoding=encoding, unlimited_dims=unlimited_dims
1930 )
[/usr/local/lib/python3.11/dist-packages/xarray/backends/api.py](https://localhost:8080/#) in dump_to_store(dataset, store, writer, encoder, encoding, unlimited_dims)
1973 variables, attrs = encoder(variables, attrs)
1974
-> 1975 store.store(variables, attrs, check_encoding, writer, unlimited_dims=unlimited_dims)
1976
1977
[/usr/local/lib/python3.11/dist-packages/xarray/backends/common.py](https://localhost:8080/#) in store(self, variables, attributes, check_encoding_set, writer, unlimited_dims)
454 writer = ArrayWriter()
455
--> 456 variables, attributes = self.encode(variables, attributes)
457
458 self.set_attributes(attributes)
[/usr/local/lib/python3.11/dist-packages/xarray/backends/common.py](https://localhost:8080/#) in encode(self, variables, attributes)
642 k: ensure_dtype_not_object(v, name=k) for k, v in variables.items()
643 }
--> 644 variables = {k: self.encode_variable(v) for k, v in variables.items()}
645 attributes = {k: self.encode_attribute(v) for k, v in attributes.items()}
646 return variables, attributes
[/usr/local/lib/python3.11/dist-packages/xarray/backends/common.py](https://localhost:8080/#) in <dictcomp>(.0)
642 k: ensure_dtype_not_object(v, name=k) for k, v in variables.items()
643 }
--> 644 variables = {k: self.encode_variable(v) for k, v in variables.items()}
645 attributes = {k: self.encode_attribute(v) for k, v in attributes.items()}
646 return variables, attributes
[/usr/local/lib/python3.11/dist-packages/xarray/backends/scipy_.py](https://localhost:8080/#) in encode_variable(self, variable)
229
230 def encode_variable(self, variable):
--> 231 variable = encode_nc3_variable(variable)
232 return variable
233
[/usr/local/lib/python3.11/dist-packages/xarray/backends/netcdf3.py](https://localhost:8080/#) in encode_nc3_variable(var)
127 data = _maybe_prepare_times(var)
128 data = coerce_nc3_dtype(data)
--> 129 attrs = encode_nc3_attrs(var.attrs)
130 return Variable(var.dims, data, attrs, var.encoding)
131
[/usr/local/lib/python3.11/dist-packages/xarray/backends/netcdf3.py](https://localhost:8080/#) in encode_nc3_attrs(attrs)
101
102 def encode_nc3_attrs(attrs):
--> 103 return {k: encode_nc3_attr_value(v) for k, v in attrs.items()}
104
105
[/usr/local/lib/python3.11/dist-packages/xarray/backends/netcdf3.py](https://localhost:8080/#) in <dictcomp>(.0)
101
102 def encode_nc3_attrs(attrs):
--> 103 return {k: encode_nc3_attr_value(v) for k, v in attrs.items()}
104
105
[/usr/local/lib/python3.11/dist-packages/xarray/backends/netcdf3.py](https://localhost:8080/#) in encode_nc3_attr_value(value)
94 value = value.encode(STRING_ENCODING)
95 else:
---> 96 value = coerce_nc3_dtype(np.atleast_1d(value))
97 if value.ndim > 1:
98 raise ValueError("netCDF attributes must be 1-dimensional")
[/usr/local/lib/python3.11/dist-packages/xarray/backends/netcdf3.py](https://localhost:8080/#) in coerce_nc3_dtype(arr)
81 cast_arr = arr.astype(new_dtype)
82 if not (cast_arr == arr).all():
---> 83 raise ValueError(
84 COERCION_VALUE_ERROR.format(dtype=dtype, new_dtype=new_dtype)
85 )
ValueError: could not safely cast array from int64 to int32. While it is not always the case, a common reason for this is that xarray has deemed it safest to encode np.datetime64[ns] or np.timedelta64[ns] values with int64 values representing units of 'nanoseconds'. This is either due to the fact that the times are known to require nanosecond precision for an accurate round trip, or that the times are unknown prior to writing due to being contained in a chunked array. Ways to work around this are either to use a backend that supports writing int64 values, or to manually specify the encoding['units'] and encoding['dtype'] (e.g. 'seconds since 1970-01-01' and np.dtype('int32')) on the time variable(s) such that the times can be serialized in a netCDF3 file (note that depending on the situation, however, this latter option may result in an inaccurate round trip).
The problem arrises from the _FillValue
chosen for the encoded variable, which is np.iinfo(np.int64).min)
:
{'dtype': 'timedelta64[s]', 'units': 'seconds', '_FillValue': np.int64(-9223372036854775808)}
Instead, when automatically converting int64
-> int32
, Xarray should also convert the automatically chosen fill value of np.iinfo(np.int64).min)
to np.iinfo(np.int32).min)
.
MVCE confirmation
- Minimal example — the example is as focused as reasonably possible to demonstrate the underlying issue in xarray.
- Complete example — the example is self-contained, including all data and the text of any traceback.
- Verifiable example — the example copy & pastes into an IPython prompt or Binder notebook, returning the result.
- New issue — a search of GitHub Issues suggests this is not a duplicate.
- Recent environment — the issue occurs with the latest version of xarray and its dependencies.
Environment
INSTALLED VERSIONS
commit: None
python: 3.11.13 (main, Jun 4 2025, 08:57:29) [GCC 11.4.0]
python-bits: 64
OS: Linux
OS-release: 6.1.123+
machine: x86_64
processor: x86_64
byteorder: little
LC_ALL: en_US.UTF-8
LANG: en_US.UTF-8
LOCALE: ('en_US', 'UTF-8')
libhdf5: 1.14.6
libnetcdf: None
xarray: 2025.6.1
pandas: 2.2.2
numpy: 2.0.2
scipy: 1.15.3
netCDF4: None
pydap: None
h5netcdf: 1.6.1
h5py: 3.14.0
zarr: None
cftime: None
nc_time_axis: None
iris: None
bottleneck: 1.4.2
dask: 2024.12.1
distributed: 2024.12.1
matplotlib: 3.10.0
cartopy: None
seaborn: 0.13.2
numbagg: None
fsspec: 2025.3.2
cupy: 13.3.0
pint: None
sparse: None
flox: None
numpy_groupies: None
setuptools: 75.2.0
pip: 24.1.2
conda: None
pytest: 8.3.5
mypy: None
IPython: 7.34.0
sphinx: 8.2.3