Skip to content

Writing timedelta64 to netCDF3 always raises an error #10466

Open
@shoyer

Description

@shoyer

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions