Skip to content

to_geotiff(pack=True) crashes on cupy and dask+cupy input #3112

@brendancol

Description

@brendancol

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggeotiffGeoTIFF modulegpuCuPy / CUDA GPU support

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions