Description
to_geotiff() validates tile_size the same way every time: positive int, and a multiple of 16 (the TIFF 6 spec requires that for TileWidth/TileLength). The check is _validate_tile_size (xrspatial/geotiff/_validation.py:235), called from to_geotiff whenever tiled or cog is true (xrspatial/geotiff/_writers/eager.py:402).
The private writer entry points underneath it don't all enforce that:
_write_streaming() (xrspatial/geotiff/_writer.py:675) validates the low-level kwargs at line 755 but skips tile_size. Pass tile_size=0 and it reaches math.ceil(width / tw) at line 817, which throws a bare ZeroDivisionError. Pass a non-multiple-of-16 value and it writes a tiled TIFF that strict libtiff/GDAL readers reject.
_write() (xrspatial/geotiff/_writer.py:278) only checks for a positive tile_size under cog=True (line 434). With tiled=True, cog=False the value goes straight to _write_tiled unchecked.
These are module-private, so not much can hit them today. But the GPU CPU-fallback path and any internal/downstream code that imports the array-level writers directly both reach them, and right now those callers can get past validation the public path would have caught.
Expected behavior
_write and _write_streaming should reject tile_size=0, negatives, non-ints, and non-multiples-of-16 with the same ValueError to_geotiff raises, whenever the path actually uses tile_size (tiled output or COG overview generation). Reuse _validate_tile_size_arg instead of duplicating the logic.
Environment
- xarray-spatial-contrib geotiff module
- Backend-independent (validation runs before any backend dispatch)
Description
to_geotiff()validatestile_sizethe same way every time: positive int, and a multiple of 16 (the TIFF 6 spec requires that for TileWidth/TileLength). The check is_validate_tile_size(xrspatial/geotiff/_validation.py:235), called fromto_geotiffwhenevertiledorcogis true (xrspatial/geotiff/_writers/eager.py:402).The private writer entry points underneath it don't all enforce that:
_write_streaming()(xrspatial/geotiff/_writer.py:675) validates the low-level kwargs at line 755 but skipstile_size. Passtile_size=0and it reachesmath.ceil(width / tw)at line 817, which throws a bareZeroDivisionError. Pass a non-multiple-of-16 value and it writes a tiled TIFF that strict libtiff/GDAL readers reject._write()(xrspatial/geotiff/_writer.py:278) only checks for a positivetile_sizeundercog=True(line 434). Withtiled=True, cog=Falsethe value goes straight to_write_tiledunchecked.These are module-private, so not much can hit them today. But the GPU CPU-fallback path and any internal/downstream code that imports the array-level writers directly both reach them, and right now those callers can get past validation the public path would have caught.
Expected behavior
_writeand_write_streamingshould rejecttile_size=0, negatives, non-ints, and non-multiples-of-16 with the sameValueErrorto_geotiffraises, whenever the path actually usestile_size(tiled output or COG overview generation). Reuse_validate_tile_size_arginstead of duplicating the logic.Environment