Describe the bug
open_geotiff(path, unpack=True, gpu=True) works since #3075, but writing the result back with to_geotiff(out, pack=True) crashes before any bytes hit disk. _pack() in xrspatial/geotiff/_attrs.py calls out.fillna(nodata), which goes through xarray's duck_array_ops.where, and that breaks on cupy-backed arrays:
- eager GPU read:
AttributeError: module 'cupy' has no attribute 'astype' (xarray calls xp.astype(condition, bool) with xp=cupy)
- dask+GPU read:
TypeError: Unsupported type <class 'numpy.ndarray'> from cupy.where when the streaming writer computes the packed graph and the host-side fill value meets a cupy chunk
Repro:
import numpy as np, xarray as xr
from xrspatial.geotiff import open_geotiff, to_geotiff
data = np.array([[1, 2, 255], [4, 5, 6]], dtype=np.uint8)
da = xr.DataArray(
data, dims=("y", "x"),
coords={"y": np.arange(2, 0, -1) - 0.5, "x": np.arange(3) + 0.5},
attrs={"crs": 4326, "nodata": 255,
"gdal_metadata": {"SCALE": "2.0", "OFFSET": "10.0"}})
to_geotiff(da, "src.tif")
g = open_geotiff("src.tif", unpack=True, gpu=True)
to_geotiff(g, "out.tif", pack=True) # AttributeError
dg = open_geotiff("src.tif", unpack=True, gpu=True, chunks=2)
to_geotiff(dg, "out2.tif", pack=True) # TypeError at compute time
Expected behavior
The same round-trip works on numpy and dask+numpy (covered by tests/write/test_pack_3064.py). The GPU writer comment in _writers/gpu.py says to_geotiff applies the re-pack before dispatch "so every write path sees the re-packed array", so the GPU path is meant to work, not raise.
The eager failure looks like the known cupy 13.6 / xarray 2025.12 where/astype incompatibility. The dask+gpu one is _pack mixing a host-side fill value into a cupy graph. Either way _pack needs a cupy-safe NaN fill, or the dependency pin plus a device-side fill value.
Environment
cupy 13.6.0, xarray 2025.12.0, dask 2025.7.0, numpy 2.3.2, Python 3.14, CUDA host.
Found by /sweep-test-coverage while adding backend coverage for pack=True. The new tests will land xfail'd against this issue.
Describe the bug
open_geotiff(path, unpack=True, gpu=True)works since #3075, but writing the result back withto_geotiff(out, pack=True)crashes before any bytes hit disk._pack()inxrspatial/geotiff/_attrs.pycallsout.fillna(nodata), which goes through xarray'sduck_array_ops.where, and that breaks on cupy-backed arrays:AttributeError: module 'cupy' has no attribute 'astype'(xarray callsxp.astype(condition, bool)withxp=cupy)TypeError: Unsupported type <class 'numpy.ndarray'>fromcupy.wherewhen the streaming writer computes the packed graph and the host-side fill value meets a cupy chunkRepro:
Expected behavior
The same round-trip works on numpy and dask+numpy (covered by
tests/write/test_pack_3064.py). The GPU writer comment in_writers/gpu.pysaysto_geotiffapplies the re-pack before dispatch "so every write path sees the re-packed array", so the GPU path is meant to work, not raise.The eager failure looks like the known cupy 13.6 / xarray 2025.12
where/astypeincompatibility. The dask+gpu one is_packmixing a host-side fill value into a cupy graph. Either way_packneeds a cupy-safe NaN fill, or the dependency pin plus a device-side fill value.Environment
cupy 13.6.0, xarray 2025.12.0, dask 2025.7.0, numpy 2.3.2, Python 3.14, CUDA host.
Found by /sweep-test-coverage while adding backend coverage for
pack=True. The new tests will land xfail'd against this issue.