Enforce stable_only=True for HTTP/fsspec sources on non-VRT read paths#2826
Merged
Conversation
) reader.http and reader.fsspec are advanced-tier in SUPPORTED_FEATURES, but stable_only=True was only gated on the VRT dispatch. The eager non-VRT path called read_to_array directly and the dask path only forwarded stable_only to read_vrt for .vrt sources, so an HTTP/fsspec source slipped through stable_only=True unchecked. - Add RemoteStableSourcesOnlyError (GeoTIFFAmbiguousMetadataError subclass), the non-VRT sibling of VRTStableSourcesOnlyError. - Add _validate_stable_only_remote and call it from open_geotiff (covers eager/dask/GPU dispatch) and from read_geotiff_dask (direct callers). - allow_experimental_codecs=True remains the documented unlock; local-file reads still pass. - Add tests across eager, dask via open_geotiff, and direct read_geotiff_dask; document the gate in geotiff.rst.
brendancol
commented
Jun 2, 2026
brendancol
left a comment
Contributor
Author
There was a problem hiding this comment.
PR Review: Enforce stable_only=True for HTTP/fsspec sources on non-VRT read paths
Blockers (must fix before merge)
None.
Suggestions (should fix, not blocking)
-
read_geotiff_gpu(xrspatial/geotiff/_backends/gpu.py:71) takesstable_onlybut does not gate remote HTTP/fsspec sources on its own. Throughopen_geotiffthe new gate runs ahead of the GPU dispatch, so the public entry point is fine. A directread_geotiff_gpu(http_url, stable_only=True)call still gets through, the same gap this PR closes for eager/dask. Out of scope for #2821 (eager + dask), but a follow-up would make all three direct entry points match. No GPU in CI to test it here anyway.
Nits (optional improvements)
- The rejection message in
_validate_stable_only_remote(xrspatial/geotiff/_validation.py:798) citesrelease_gate_geotiff.rstand epic #2342, matching_validate_stable_only_vrt. The doc that actually describes this gate isgeotiff.rst, not the release-gate checklist. The sibling validator does the same, so leaving it is fine.
What looks good
- The gate sits in
open_geotiffahead of the eager/dask/GPU dispatch (__init__.py:917), with a direct check inread_geotiff_dask(_backends/dask.py), so both the routed and direct dask paths are covered. _validate_stable_only_remotemirrors_validate_stable_only_vrt: same early returns, sameallow_experimental_codecsunlock, same error family (GeoTIFFAmbiguousMetadataError).sourceis already normalized by_coerce_pathbefore the gate, so path-like inputs are strings by the time_is_fsspec_urisees them.- Tests cover eager, dask via
open_geotiff, directread_geotiff_dask, thehttp://case (gated before any fetch), the experimental-codecs unlock, and both local-file backends still passing.
Checklist
- Behavior matches the VRT gate it mirrors
- Targeted backends (eager, dask) gated and tested
- Error type/message consistent with the existing VRT path
- Edge cases covered (local file passes, http gated pre-fetch, unlock works)
- No premature materialization (gate runs before any read)
- Benchmark not needed (validation-only change)
- Docstrings present and accurate
- Doc updated (geotiff.rst)
brendancol
commented
Jun 2, 2026
brendancol
left a comment
Contributor
Author
There was a problem hiding this comment.
Review follow-up
No new commits: both findings were resolved without code changes in this PR.
- Suggestion (direct
read_geotiff_gpudoes not gate remote sources): deferred to #2830. It is GPU-only and was out of scope for the eager + dask finding in #2821. The publicopen_geotiff(..., gpu=True)path is already covered by the shared gate in this PR; only the direct GPU entry point remains, which #2830 tracks. - Nit (error message cites
release_gate_geotiff.rstrather thangeotiff.rst): dismissed. The citation matches the sibling_validate_stable_only_vrtvalidator on purpose. Changing one and not the other would split the convention, and the review itself flagged leaving it as fine.
The new error is exported in xrspatial.geotiff.__all__, so the frozen public-API contract test (test_all_lists_supported_functions) and the _errors.__all__ list both have to include it. CI caught the missing entries on the eager fast-lane job.
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 #2821
reader.httpandreader.fsspecare advanced-tier inSUPPORTED_FEATURES, butstable_only=Truewas only gated on the VRT dispatch. The eager non-VRT path calledread_to_arraydirectly, and the dask path only forwardedstable_onlytoread_vrtfor.vrtsources, so an HTTP/fsspec source read straight throughstable_only=Trueunchecked.Changes
RemoteStableSourcesOnlyError(aGeoTIFFAmbiguousMetadataErrorsubclass), the non-VRT sibling ofVRTStableSourcesOnlyError, and re-export it fromxrspatial.geotiff._validate_stable_only_remoteand call it fromopen_geotiff(covers the eager/dask/GPU dispatch) and fromread_geotiff_dask(direct callers). It rejectshttp(s)://and fsspec URIs understable_only=Truebefore any fetch or decode.allow_experimental_codecs=Truestays the documented unlock; local-file reads still pass.docs/source/reference/geotiff.rst.Backends
The gate lives in
open_geotiffahead of the eager / dask / GPU dispatch, plus a direct check inread_geotiff_dask. CPU eager and CPU dask are covered by the new tests; the GPU dispatch path shares the sameopen_geotiffgate (no GPU hardware in CI to assert directly).Test plan
stable_only=TrueraisesRemoteStableSourcesOnlyErroropen_geotiffand directread_geotiff_dask) raiseshttp://source raises before any network fetchallow_experimental_codecs=Trueunlocks the readstable_only=True