Skip to content

Narrow except Exception in read_vrt to OSError/ValueError/struct.error (#1670)#1675

Merged
brendancol merged 2 commits into
mainfrom
issue-1670
May 12, 2026
Merged

Narrow except Exception in read_vrt to OSError/ValueError/struct.error (#1670)#1675
brendancol merged 2 commits into
mainfrom
issue-1670

Conversation

@brendancol
Copy link
Copy Markdown
Contributor

Summary

read_vrt wrapped each source read in except Exception. In default mode the "skip this tile" fallback would swallow any Exception subclass, including RuntimeError and MemoryError from unrelated bugs. The catch was only ever meant for unreadable source files.

Restrict the catch to what read_to_array actually raises for an unreadable or malformed source:

  • OSError and subclasses (FileNotFoundError, PermissionError) for I/O failures
  • ValueError for the typed parse errors from parse_header / parse_ifd
  • struct.error, which still leaks from a couple of parse paths until those get cleaned up

The strict-mode escape from #1662 and the warning text are unchanged.

Test plan

  • New test module test_vrt_narrow_except_1670.py with 9 tests:
    • RuntimeError propagates in both default and strict modes (previously swallowed in default)
    • MemoryError propagates in default mode
    • FileNotFoundError warns and continues in default, re-raises in strict
    • ValueError warns and continues in default, re-raises in strict
    • struct.error warns and continues in default
    • PermissionError warns and continues in default
  • Pre-fix test confirmed the bug: DID NOT RAISE <class 'RuntimeError'>
  • Existing VRT tests pass (78 vrt-keyword tests, 125 in full geotiff tests dir)
  • Existing strict-mode tests pass (22 in test_strict_mode_1662.py)

Closes #1670

@github-actions github-actions Bot added the performance PR touches performance-sensitive code label May 12, 2026
@brendancol brendancol requested a review from Copilot May 12, 2026 15:15
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR narrows the exception handler in the GeoTIFF VRT reader so that default-mode “skip this tile” behavior no longer swallows arbitrary bugs (e.g., RuntimeError, MemoryError), while keeping strict-mode (XRSPATIAL_GEOTIFF_STRICT=1) behavior unchanged.

Changes:

  • Narrow read_vrt’s per-source except Exception to except (OSError, ValueError, struct.error).
  • Add a regression test module asserting propagation vs warn-and-continue behavior for several exception types.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
xrspatial/geotiff/_vrt.py Narrows the exception allowlist for per-source reads inside VRT assembly.
xrspatial/geotiff/tests/test_vrt_narrow_except_1670.py Adds regression tests for the new exception-handling contract (default vs strict mode).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread xrspatial/geotiff/_vrt.py Outdated
Comment on lines +367 to +371
src.filename,
window=(src_r0, src_c0, src_r1, src_c1),
band=src.band - 1, # convert 1-based to 0-based
)
except Exception as e:
except (OSError, ValueError, struct.error) as e:
brendancol added a commit that referenced this pull request May 12, 2026
Addresses Copilot feedback on PR #1675: the narrowed
(OSError, ValueError, struct.error) catch in read_vrt did not cover
codec-specific exceptions raised from corrupt compressed tiles, which
meant a single bad deflate or ZSTD payload aborted the whole mosaic
instead of warning-and-skipping like the historical behaviour.

Expand the allowlist via a small helper that returns the tuple of
codec-library decode errors worth swallowing (zlib.error always;
zstandard.ZstdError when the optional dep is installed). RuntimeError
is deliberately left out since lz4 frame, LERC and glymur all raise it
for both corruption and real bugs.
#1670)

The VRT source-read fallback in ``_vrt.py`` caught every ``Exception``
subclass, so a ``RuntimeError`` or ``MemoryError`` thrown by future code
paths would silently turn into a warn-and-skip "hole" in the mosaic. The
intent was always "this one source file is unreadable, fall back to fill
values"; widen-to-Exception leaked real bugs.

Restrict the catch to the families ``read_to_array`` actually
documents/raises: ``OSError`` (and ``FileNotFoundError`` /
``PermissionError``) for I/O, ``ValueError`` for the typed parse errors,
and ``struct.error`` which still leaks from a couple of parse paths
until that gets cleaned up. Strict mode (#1662) and the warning text
are unchanged.
Addresses Copilot feedback on PR #1675: the narrowed
(OSError, ValueError, struct.error) catch in read_vrt did not cover
codec-specific exceptions raised from corrupt compressed tiles, which
meant a single bad deflate or ZSTD payload aborted the whole mosaic
instead of warning-and-skipping like the historical behaviour.

Expand the allowlist via a small helper that returns the tuple of
codec-library decode errors worth swallowing (zlib.error always;
zstandard.ZstdError when the optional dep is installed). RuntimeError
is deliberately left out since lz4 frame, LERC and glymur all raise it
for both corruption and real bugs.
@brendancol brendancol merged commit 8d21bde into main May 12, 2026
10 of 11 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.

VRT source-read except Exception should narrow to I/O and parse errors

2 participants