Skip to content

Skip empty multipolygons in union_many() to avoid invalid R-tree box - #927

Merged
systemed merged 1 commit into
systemed:masterfrom
geoneutrino:fix-empty-multipolygon-union
Aug 29, 2026
Merged

Skip empty multipolygons in union_many() to avoid invalid R-tree box#927
systemed merged 1 commit into
systemed:masterfrom
geoneutrino:fix-empty-multipolygon-union

Conversation

@geoneutrino

Copy link
Copy Markdown
Contributor

Generating planet tiles crashes during the mbtile write phase with a
Boost.Geometry assertion:

boost/geometry/index/rtree.hpp:1661:
Assertion `(detail::is_valid(m_members.translator()(value)))
&& ("Indexable is invalid")' failed.
Aborted

Environment

Debian 13.6
libboost-dev 1.83.0.2+b2
git pull master to update my version with the commits of the last 3 months
make clean
make => NDEBUG not set so an assert causes abort() which results in the crash (while with NDEBUG this error is silently ignored)
planet dump of this week (Aug. 27), problematic tile extract attached

Cause

boost::geometry::envelope() of an empty multipolygon returns Boost's inverse
initialisation box — min = +DBL_MAX, max = -DBL_MAX — which fails
the indexable validity check on insert.

Clipping a polygon against a tile boundary can legitimately produce an
empty result, so ProcessObjects() (tile_worker.cpp:402) can hand
union_many() a vector containing empty entries.

Backtrace at the point of failure:

#4 ...rtree<...>::raw_insert (...) at boost/geometry/index/rtree.hpp:1661
#6 union_many (to_unify=std::vector of length 2) at src/geom.cpp:257
#7 ProcessObjects (...) at src/tile_worker.cpp:402
#8 ProcessLayer (..., zoom=13, ...) at src/tile_worker.cpp:496

with to_unify[0].empty() == true and the box printing as
±1.7976931348623157e+308.

Fix

Skip empty multipolygons before the R-tree query and insert. An empty
multipolygon cannot intersect anything and contributes nothing to the
union, so skipping it is semantically correct rather than just
silencing the assertion.

Why this matters for release builds

Builds that define NDEBUG — including CMake Release and most
distribution packages — compile the assertion out. They do not abort,
but they do store the invalid box in the R-tree, which makes
subsequent intersects() queries unreliable for that tile. Polygons
may then be merged that should not be, or vice versa. The result is
silently incorrect output rather than a crash.

The Makefile build does not define NDEBUG, which is why the problem
surfaces there.

Reproduction

Planet dump, z13 within z6/0/14 (north-west Alaska). A cut-down
extract is enough (attached)

osmium extract -b -180,67.5,-172,71.5 planet-latest.osm.pbf -o problem.osm.pbf
tilemaker --input problem.osm.pbf --output problem.mbtiles \
  --config config.json --process process.lua

boost::geometry::envelope() of an empty multipolygon returns Boost's inverse
initialisation box (min = +DBL_MAX, max = -DBL_MAX). Inserting that
box into the R-tree trips the Boost.Geometry indexable validity
check, aborting the run:

  boost/geometry/index/rtree.hpp:1661:
  Assertion `is_valid(...) && "Indexable is invalid"' failed.

Clipping a polygon against a tile can legitimately produce an empty
result, so ProcessObjects() can hand union_many() a vector whose
entries are empty. An empty multipolygon cannot intersect anything
and contributes nothing to the union, so skip it before the R-tree
query and insert.

Builds that define NDEBUG do not abort, but store the invalid box in
the R-tree, which makes subsequent intersects() queries unreliable
for that tile. The result is silently wrong output rather than a
crash, so this affects release builds too.

Reproduced on a planet dump at z13 in z6/0/14 (north-west Alaska,
bbox -180,67.5,-172,71.5).
@systemed

Copy link
Copy Markdown
Owner

Thanks! I think this might be similar to 67f1e45 which is in a branch hopefully to be merged later today. I'll compare the two in practice.

@systemed
systemed merged commit f2a87f9 into systemed:master Aug 29, 2026
11 of 12 checks passed
@systemed

Copy link
Copy Markdown
Owner

Yep, it's the same. I'll merge this, back out the fix in the declutter branch and then re-merge. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants