Validate gpu dispatch flag as bool, fail closed (#2819)#2823
Merged
Conversation
The gpu flag selected the GPU backend by truthiness on both the read (open_geotiff) and write (to_geotiff) paths. A non-bool like gpu="False" is truthy, so it routed to the GPU path instead of raising. bool is also an int subclass, so gpu=1 / gpu=0 slipped past int-style guards. Add a shared _validate_gpu_arg helper that rejects non-bool gpu with TypeError before any branch reads it. The read path requires a bool (default False); the write path also accepts None, its auto-detect sentinel. np.bool_ is accepted alongside Python bool, matching the existing nodata validation. Read-path validation lives in _validate_dispatch_kwargs, so the direct dask / gpu / vrt backends inherit the same check.
brendancol
commented
Jun 2, 2026
Contributor
Author
brendancol
left a comment
There was a problem hiding this comment.
PR Review: Validate gpu dispatch flag as bool, fail closed (#2819)
Blockers (must fix before merge)
None.
Suggestions (should fix, not blocking)
None.
Nits (optional improvements)
xrspatial/geotiff/_validation.py: the read-path call passesgpustraight fromopen_geotiff'sgpu: bool = Falsedefault, so the new check also runs for the three direct backends (read_geotiff_dask,read_geotiff_gpu,read_vrt) that route through_validate_dispatch_kwargs.read_geotiff_gpuhardcodesgpu=Trueinto the validator, so its own deprecated string parameter (gpu='strict'/'auto'/'loose', the legacyon_gpu_failurealias) is untouched. A one-line note in the helper docstring saying the validatedgpuis the dispatch bool, not that legacy alias, would save a future reader from conflating the two. Optional.
What looks good
- The check lands before any branch reads
gpuon both paths: read path inside_validate_dispatch_kwargs, ahead of theon_gpu_failureand file-like guards; write path at the top ofto_geotiff, ahead of theuse_gpuresolution. I confirmed no earliergpuread exists in either function. allow_nonemodels the real signature difference. The read path isboolonly; the write path isbool | NonewithNoneas the auto-detect sentinel.- Accepting
np.bool_next toboolmatches the existingnodatavalidation, so the two type guards stay consistent. - Tests cover the important cases: parametrized non-bool rejection on both paths, the
None-rejected-on-read vsNone-valid-on-write asymmetry, validation firing before file I/O on read, and the positive cases (True/False/np.bool_) still dispatching.
Checklist
- Algorithm matches reference/paper: n/a (input validation)
- All implemented backends consistent: yes, read-path check shared via
_validate_dispatch_kwargs - NaN handling correct: n/a
- Edge cases covered by tests: yes
- Dask chunk boundaries handled correctly: n/a
- No premature materialization or unnecessary copies: confirmed
- Benchmark exists or not needed: not needed
- README feature matrix updated: not needed, no new function
- Docstrings present and accurate: yes
brendancol
commented
Jun 2, 2026
Contributor
Author
brendancol
left a comment
There was a problem hiding this comment.
PR Review (follow-up): Validate gpu dispatch flag as bool, fail closed (#2819)
The one Nit from the previous review is addressed in 4cfc329: the _validate_dispatch_kwargs docstring now spells out that its gpu parameter is the dispatch bool (type-checked via _validate_gpu_arg), distinct from read_geotiff_gpu's deprecated gpu='strict'/'auto'/'loose' string alias, which never reaches this helper.
No new findings. No Blockers, no Suggestions.
What looks good
gpuvalidation fires before any branch reads the flag on both the read and write paths.np.bool_accepted alongsidebool, consistent with the existingnodataguard.- Test coverage spans non-bool rejection on both paths, the read/write
Noneasymmetry, validation-before-IO on read, and the positiveTrue/False/np.bool_cases.
Checklist
- Algorithm matches reference/paper: n/a (input validation)
- All implemented backends consistent: yes
- NaN handling correct: n/a
- Edge cases covered by tests: yes
- No premature materialization or unnecessary copies: confirmed
- Benchmark exists or not needed: not needed
- README feature matrix updated: not needed
- Docstrings present and accurate: yes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2819
What changed
gpuselected the GPU backend by truthiness on both entry points, so a non-bool likegpu="False"was truthy and silently routed to the GPU path instead of raising.boolis also anintsubclass, sogpu=1/gpu=0slipped through._validate_gpu_argin_validation.py. It rejects non-boolgpuwithTypeErrorbefore any branch reads the flag.open_geotiff): validation runs inside_validate_dispatch_kwargs, so the direct dask / gpu / vrt backends inherit the same check.gpumust be a bool (defaultFalse).to_geotiff): validated at the top of the function, beforeuse_gpuresolution.Nonestays valid as the auto-detect-from-data sentinel.np.bool_is accepted alongside Pythonbool, matching hownodatavalidation already treats(bool, np.bool_).Backend coverage
Dispatch-flag validation, backend-agnostic. The read-path check is shared across numpy / dask / cupy / dask+cupy through
_validate_dispatch_kwargs; the write-path check runs once at theto_geotiffentry point.Test plan
gpu="False",gpu="True",gpu=1,gpu=0,gpu=1.0,gpu=[True]raiseTypeErroron both read and write pathsgpu=True/gpu=Falsestill dispatch as before; write pathgpu=Noneauto-detects;np.bool_acceptedTypeError)