Repository navigation
Description
What's broken
Issue #1752 added tile_size and chunks validation to to_geotiff and read_geotiff_dask. The matching kwargs on three sibling entry points were skipped, so they still reach the deeper writer/dask paths with invalid values and surface confusing errors that do not name the bad parameter.
The gaps:
-
write_geotiff_gpu(tile_size=)is missing the validationto_geotiffdoes. The four cases geotiff: validate tile_size and dask chunks at entry points #1752 covers forto_geotiff:tile_size=0raisesZeroDivisionErrorfromgpu_compress_tilestile_size=-1raisesstruct.error('H' format requires 0 <= number <= 65535)tile_size=FalseraisesZeroDivisionError(bool slipped through becauseFalse == 0)tile_size=256.0raisesTypeError('float' object cannot be interpreted as an integer)
-
read_geotiff_gpu(chunks=)is missing the validationread_geotiff_daskdoes:chunks=0raisesZeroDivisionErrorchunks=-1silently produces output (no validation at all)chunks=(0, 256)raisesZeroDivisionErrorchunks=(256, -1)silently produces output
-
read_vrt(chunks=)is missing the same validation as 2.
open_geotiff(chunks=) is fine on the CPU path because it routes through read_geotiff_dask's already-validated branch. The gap shows up for open_geotiff(gpu=True, chunks=X), direct read_geotiff_gpu(chunks=X), and read_vrt(chunks=X).
How to reproduce
import numpy as np
import xarray as xr
import cupy
import os
import tempfile
from xrspatial.geotiff import (
write_geotiff_gpu, read_geotiff_gpu, read_vrt,
to_geotiff, write_vrt,
)
arr = np.arange(100, dtype=np.float32).reshape(10, 10)
da = xr.DataArray(arr, dims=['y', 'x'])
with tempfile.TemporaryDirectory() as d:
tif = os.path.join(d, 'a.tif')
to_geotiff(da, tif)
vrt = os.path.join(d, 'a.vrt')
write_vrt(vrt, [tif])
write_geotiff_gpu(xr.DataArray(cupy.asarray(arr), dims=['y', 'x']),
os.path.join(d, 'out.tif'),
tile_size=0) # ZeroDivisionError
read_geotiff_gpu(tif, chunks=0) # ZeroDivisionError
read_geotiff_gpu(tif, chunks=-1) # silently passes
read_vrt(vrt, chunks=-1) # silently passes
Suggested fix
Mirror the up-front guard #1752 added to to_geotiff and read_geotiff_dask:
write_geotiff_gpu: reject non-positive int or non-inttile_sizewith aValueErrornaming the parameter.read_geotiff_gpuandread_vrt: reject non-positive int or non-intchunks(and tuple-of-non-positive, and wrong-length tuple) with the same message formatread_geotiff_daskuses.
Source touches are small; the guards already exist on the sibling entry points and can be reused.
Tests
Tests that should be added in the same PR:
tile_size=0,tile_size=-1,tile_size=256.0,tile_size=True/Falseonwrite_geotiff_gpuchunks=0,chunks=-1,chunks=(0, N),chunks=(N, -1), wrong-length tuple, non-int onread_geotiff_gpuandread_vrt- Positive int and
np.int64scalar still work (regression pin against the integer-scalar branch).
Surfaced by the test-coverage sweep on the geotiff module (pass 13, 2026-05-13).
Activity
geotiff: add allow_none to _validate_chunks_arg so read_geotiff_dask …
geotiff: validate tile_size and chunks on write_geotiff_gpu/read_geot…
geotiff: add allow_none to _validate_chunks_arg so read_geotiff_dask …
geotiff: extend #1752 size-arg validation to write_geotiff_gpu / read…
geotiff: extract input validators to _validation.py (#1882) (#1892)
geotiff: extract writers to _writers/, reduce __init__.py to dispatch (…