Topology Errors in a GeoJSON: Detect Without Fixing
In Geometry validity of a GeoJSON we repaired polygons that were individually invalid with make_valid()/st_make_valid(). Here the problem is different: every single feature’s geometry can be perfectly valid, and the dataset can still be broken: two polygons that overlap, a gap between two areas that should touch, a line that ends a millimeter from another without connecting.
This tool doesn’t fix anything. It detects, describes and locates the errors. Closing a gap or assigning an overlap is a semantic decision (which polygon is the “correct” one?) that no algorithm can make for you: it’s a data-quality report, not an automatic repair tool.
On load, the code detects whether your data is polygons or lines and runs only the checks that make sense for that type:
- Polygons → overlap, gap, sliver, duplicates
- Lines → dangle, duplicates
Just want to quickly check a file, without the rest of the reading? Use the standalone tool — same engine, less prose.
1. Upload your file
A .geojson, or a shapefile: either as a single .zip, or as the individual .shp/.dbf/.shx files (and optionally .prj) selected together.
2. What we look for
Five recurring categories, drawn from the USGS catalog and from the QGIS Topology Checker:
4. Five errors, five examples
4.1 Overlap
Two polygons that should be adjacent instead overlap over a portion of surface: the example already loaded by default in the cell pair above.
4.2 Gap
Two aligned polygons that should cover a single continuous area instead leave a gap between them. It’s detected by comparing the union of the polygons with the convex hull containing both.1
1 The gap is shown as its own feature (a synthetic geometry, not one of yours), colored like the other error rows. The check only looks at polygon pairs that are close and not already overlapping, using the convex hull of the single pair, not of the whole dataset (that would flag as “gap” even the simple fact that two distant or overlapping shapes aren’t aligned with each other). For a real dataset with a known study area, that area is still the more correct reference, not a convex hull.
4.3 Sliver
An extremely thin polygon (0.1° wide, 0.001° tall), a typical leftover from an overlay between nearly coincident boundaries. Detected with the Polsby-Popper compactness index (4π·area/perimeter²): below 0.15 is considered a sliver.2
2 The index is bounded at the most compact shape possible for a given perimeter (a circle scores exactly 1), so 0.15 means “less than a sixth as compact as the roundest shape with the same perimeter would be,” not an arbitrary cutoff. A perfect square scores about 0.785, for a sense of scale between the two.
4.4 Duplicates
Two features with identical geometry, something that happens often during merges or repeated imports. The check applies the same way to polygons and lines (topological equality), shown here on polygons.
4.5 Dangle
A line network where three segments form a closed loop (each end touches exactly the next segment’s end, no dangle) and a fourth stays isolated, with both ends “dangling”. Notice how the layer on the map switches from fill to line: the code itself decides that, based on the geometry type you feed it.
5. Apply to your file
The cells below try to read /uploaded.geojson, then an uploaded shapefile (/uploaded.shp), then a zipped shapefile (or, without an upload, use the overlap example as test data), detect the geometry type and automatically apply only the relevant checks — same detect_and_check() function as every example above, no duplicated logic.
6. Knowing what’s broken is already a result
A report that says “23 overlaps, 8 gaps, 4 slivers” isn’t half a tool: it’s a legitimate, complete quality-assurance step in its own right. Fixing these errors almost always requires a human decision: which polygon to move, who to assign a gap to, whether a 2 m² sliver is noise or a real island. A future article may cover repair strategies; this one deliberately stops before that, where geometry alone can no longer answer the question.