Skip to content

Gate stable_only=True before bbox metadata read on remote/VRT sources#2882

Merged
brendancol merged 2 commits into
mainfrom
issue-2869
Jun 3, 2026
Merged

Gate stable_only=True before bbox metadata read on remote/VRT sources#2882
brendancol merged 2 commits into
mainfrom
issue-2869

Conversation

@brendancol
Copy link
Copy Markdown
Contributor

Closes #2869

open_geotiff(..., bbox=...) resolved the bounding box to a pixel window before the stable_only=True rejection ran for remote and VRT sources. The bbox resolver reads source geo metadata first: the TIFF path reads a header (a range GET for an HTTP/fsspec source) and the VRT path parses the VRT XML. Both stable-only gates only fired after that, so a stable_only=True request could trigger remote I/O or a VRT parse before it got refused. The docstring on _validate_stable_only_remote requires the rejection to land before any range GET or decode work.

Changes

  • Move both stable-only gates ahead of bbox resolution in open_geotiff: _validate_stable_only_vrt for .vrt sources, _validate_stable_only_remote otherwise. Each helper is a no-op for the wrong source type.
  • Drop the old post-VRT-branch _validate_stable_only_remote call, now redundant since the gate runs earlier. read_vrt keeps its own gate for direct callers, so the VRT path still fails closed on both entry points.

Backend coverage

Dispatcher-level validation, so it applies uniformly across numpy / dask. The fsspec + bbox case is exercised through both the eager and dask dispatch paths. No GPU or numerical kernel change.

Test plan

  • test_stable_only_bbox_ordering_2869.py: remote (HTTP + fsspec) and VRT bbox + stable_only combinations, each pointed at a source whose bbox read would raise a different error (fetch failure / XML ParseError) if it ran first, so the typed stable-only error proves the gate runs ahead of the read.
  • Positive controls: allow_experimental_codecs=True still resolves the bbox and reads for both fsspec and VRT sources.
  • Existing test_stable_only_remote_2821.py, bbox suites, and the geotiff release-gate tests pass unchanged.

…#2869)

open_geotiff(..., bbox=...) resolved the bbox to a pixel window before
the stable_only=True rejection ran for remote and VRT sources. The bbox
resolver reads source geo metadata first (a header range GET for an
HTTP/fsspec source, a VRT XML parse for a .vrt source), so a stable-only
request could trigger remote I/O or a VRT parse before it was refused.
That breaks the ordering contract on _validate_stable_only_remote.

Move both stable-only gates ahead of bbox resolution: _validate_stable_only_vrt
for .vrt sources, _validate_stable_only_remote otherwise. The old post-VRT
remote gate is removed since it now runs earlier. read_vrt keeps its own
gate for direct callers.

Adds tests covering remote+bbox+stable_only and vrt+bbox+stable_only,
each pointed at a source whose bbox read would raise a different error
if it ran first, so the typed stable-only error proves the ordering.
Copy link
Copy Markdown
Contributor Author

@brendancol brendancol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review: Gate stable_only=True before bbox metadata read on remote/VRT sources

Blockers (must fix before merge)

None.

Suggestions (should fix, not blocking)

None.

Nits (optional improvements)

  • xrspatial/geotiff/__init__.py:859-870: moving the stable-only gate above the bbox block also moves it above the window=/bbox= mutual-exclusion ValueError (now at :880-884). So open_geotiff(remote, window=X, bbox=Y, stable_only=True) now raises the stable-only error instead of the mutual-exclusion error. That precedence is defensible (reject the unsupported tier before validating kwargs that won't be honored anyway) and probably more correct, but it is a small change in error ordering that nothing tests. Optional: note it in the comment, or leave as-is.

What looks good

  • The fix matches the contract documented on _validate_stable_only_remote ("before any range GET or decode work") and extends the same ordering to the VRT XML parse.
  • Tests are well-targeted. Each points at a source whose bbox read would raise a distinct error (fetch failure / xml ParseError) if it ran first, so the typed stable-only error proves the ordering rather than just the eventual rejection. The negative control (malformed VRT without stable_only still hits ParseError) confirms the fixture exercises the path being short-circuited.
  • The redundant post-VRT-branch _validate_stable_only_remote call is removed cleanly. read_vrt keeps its own gate, so direct callers still fail closed.
  • Positive controls with allow_experimental_codecs=True confirm the bbox still resolves and reads when the tier is unlocked.

Checklist

  • Validation ordering matches the documented contract
  • Remote (HTTP + fsspec) and VRT bbox paths covered by tests
  • Eager and dask dispatch paths both exercised
  • No new public API; no README or notebook needed
  • No numerical/kernel change; backend parity not affected
  • Diff is surgical, no unrelated edits

…nce (#2869)

The stable-only gate now runs ahead of the window=/bbox= mutual-exclusion
check. Note that precedence in the comment and add a test pinning it: a
remote source under stable_only=True with both window= and bbox= reports
the tier rejection, not the kwarg conflict.
@github-actions github-actions Bot added the performance PR touches performance-sensitive code label Jun 2, 2026
Copy link
Copy Markdown
Contributor Author

@brendancol brendancol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up review

The one nit from the first pass is addressed in a1c75a2:

  • The comment at xrspatial/geotiff/__init__.py:854-861 now spells out that the stable-only gate runs ahead of the window=/bbox= mutual-exclusion check, so the tier rejection wins.
  • test_stable_only_wins_over_window_bbox_conflict pins that precedence: a remote source under stable_only=True with both window= and bbox= reports RemoteStableSourcesOnlyError, not the kwarg conflict.

No new findings. The full test_stable_only_bbox_ordering_2869.py suite (8 tests) passes, along with the existing stable-only, bbox, and geotiff release-gate suites. The branch is even with origin/main with no conflicts. Nothing blocking.

@brendancol brendancol merged commit 49a6423 into main Jun 3, 2026
7 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance PR touches performance-sensitive code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

stable_only=True enforced after bbox metadata read on remote/VRT sources

1 participant