Guard rasterize() against geometry/like CRS mismatch (#3058) - #3062
Merged
Conversation
brendancol
commented
Jun 9, 2026
brendancol
left a comment
Contributor
Author
There was a problem hiding this comment.
PR Review: Guard rasterize() against geometry/like CRS mismatch (#3058)
Blockers (must fix before merge)
None.
Suggestions (should fix, not blocking)
_like_crswraps therio.crslookup in a bareexcept Exception(rasterize.py:3010-3015). That matches the broad catch inpolygonize._detect_raster_crs, so it is consistent with the codebase, but it also swallows a real rioxarray error (say a corrupt spatial_ref) and falls through toNone, which disables the guard for that template. Since the resolution order checksattrs['crs'],attrs['crs_wkt'], and thespatial_refcoord first, this only bites templates that rely solely onrio.crs, so it is minor. A short comment on the intent would help; matching the existing helper is defensible either way.
Nits (optional improvements)
- The mismatch error embeds
geom_crs!r, which for a geopandas frame is a multi-line pyproj CRS repr, so the message runs long.accessor._open_geotiff_windoweddoes the same thing, so it is consistent, but ato_epsg()-style summary would read better. Not blocking.
What looks good
- The guard runs before backend dispatch and before any host or device allocation, so it behaves the same across numpy, cupy, dask+numpy, and dask+cupy with no per-backend code.
- CRS resolution in
_like_crsfollows the same order aspolygonize._detect_raster_crs, so a template round-trips the same CRS through rasterize and polygonize. - Both sides go through
pyproj.CRSbefore.equals(), so int EPSG, "EPSG:xxxx" strings, and WKT all compare correctly. Same precedent asaccessor.py. - The
check_crs=Falseopt-out is documented and tested, and the no-op-when-either-side-is-None behavior keeps CRS-less inputs working unchanged. - Tests cover the attrs, crs_wkt, and spatial_ref resolution paths, the bypass, int-vs-string equivalence, invalid-CRS surfacing, and the dask and cupy backends.
Checklist
- Algorithm matches reference/paper (N/A, validation guard)
- All implemented backends produce consistent results (guard pre-dispatch)
- NaN handling is correct (unchanged by this PR)
- Edge cases are covered by tests
- Dask chunk boundaries handled correctly (guard runs before chunking)
- No premature materialization or unnecessary copies
- Benchmark exists or is not needed (not needed, validation-only)
- README feature matrix updated (N/A, no new function or backend change)
- Docstrings present and accurate
brendancol
commented
Jun 9, 2026
brendancol
left a comment
Contributor
Author
There was a problem hiding this comment.
Follow-up review (after fixes)
Both findings from the first pass are resolved.
- Suggestion (bare except in
_like_crs): added a comment at rasterize.py:3014 explaining the broad catch is deliberate..rioraises AttributeError without rioxarray, andrio.crscan raise on a malformed georeference, so either way the template is treated as having no detectable CRS and the attrs/spatial_ref paths stay the source of truth. Behavior is unchanged on purpose; narrowing the type would break the no-rioxarray path. - Nit (long pyproj repr in the error): the mismatch message now labels each side with a compact
EPSG:xxxx, falling back to the CRS name when no EPSG code exists. A new test asserts the message is single-line and contains both codes.
Tests: 17 in the new file, all green; the full rasterize suite is still 231 passed, 2 skipped. flake8 clean.
No new issues found.
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 #3058
What
rasterize(geometries, like=template)no longer silently burns geometries onto a template in a different CRS._parse_inputnow returns the GeoDataFrame's.crsinstead of dropping it._like_crshelper reads the template CRS (attrs['crs'],attrs['crs_wkt'], thespatial_refcoord, orrio.crs), matchingpolygonize._detect_raster_crs.rasterizenormalizes them through pyproj and raisesValueErroron mismatch. A newcheck_crs=Trueparameter (default) gates this;check_crs=Falseopts out.Why
_parse_inputdiscardedgdf.crswhile_extract_grid_from_likepropagated the template CRS onto the output. So an EPSG:4326 GeoDataFrame rasterized onto an EPSG:3857 template came back tagged EPSG:3857, with no reprojection and no warning. It looked authoritative but was wrong.The geometries are never reprojected; reproject them to match the template, or pass
check_crs=Falseto burn onto the template grid anyway.Backend coverage
The guard runs before backend dispatch, so it behaves the same for numpy, cupy, dask+numpy, and dask+cupy. Tests cover the numpy path plus the dask and cupy paths.
Test plan
check_crs=Falsebypassesattrs['crs'],attrs['crs_wkt'], and thespatial_refcoord(geometry, value)iterable path"EPSG:xxxx"string compare equal