Geometry validity: find and understand invalid geometries

tool
geometry
bilingual
An interactive lab with Python, R and MapLibre — upload a GeoJSON, find out which geometries are invalid and why, compare how the two languages diagnose the same problem. Repair is a separate, optional step.
Published

August 29, 2026

Upload a GeoJSON, find out which geometries are invalid and why, and run the same diagnosis in Python and in R on the same map — repair (make_valid()/st_make_valid()) is a separate, optional step, at the bottom of the page.

A .geojson, or a shapefile (either as a single .zip, or as .shp/.dbf/.shx selected together) — see the section below.

Just want to quickly validate or fix a file, without the rest of the reading? Use the standalone tool — same engine, less prose.

Can a polygon look normal and still be invalid?

flowchart TD
    A["Looks fine on the map"] --> B["Polygon"]
    B --> C["Geometry validator"]
    C --> D["❌ INVALID"]
    D --> E["Why?"]

Yes — a polygon can have a boundary that crosses itself, a hole that extends outside the outer boundary, or two holes that overlap, and it’s not uncommon for the shape on the map to look perfectly fine. Below you can find out exactly what to look for, in your own file or in one of the four ready-made examples further down.

Shared map and table

A single map and table, shared by every example on the page: run the same diagnosis in Python or R and compare the result here.

Geometry validity feature, valid, invalid.

Diagnose: validate your geometry

Run the same check in Python or R on the current data (your file uploaded above, or the example already loaded below) — no repair yet, just diagnosis: is the geometry valid? If not, why?

Same spatial question, two languages

Python and R answer the same question with one line each:

Python

gdf.geometry.is_valid

R

sf::st_is_valid(data)

Both go through the same geometry engine, GEOS, for this calculation — but don’t expect the exact same text when you ask why a geometry is invalid: explain_validity() in Python includes the coordinates of the problem (e.g. "Self-intersection[12.5 41.9]"), while st_is_valid(reason = TRUE) in R describes the edges involved without coordinates (e.g. "Edge 0 crosses edge 2") — same calculation, different vocabulary. It’s exactly the kind of detail that distinguishes one spatial ecosystem from the other, not a bug in either one.

Valid according to whom?

“Valid” isn’t absolute: it depends on the geometric model and the engine checking it.

  • Pythonshapely → always GEOS.
  • Rsf → GEOS or S2, depending on sf::sf_use_s2().

For the diagnosis above the difference doesn’t show. It becomes concrete in the repair, below:

Important

Why sf_use_s2(FALSE) before st_make_valid()? With geographic coordinates (lon/lat) and sf_use_s2(TRUE) (the default), st_make_valid() in R dispatches to s2::s2_rebuild() instead of GEOS — a different algorithm that, on these cases, fixes nothing, returning the geometry unchanged without an error. Verified not just on webR but also on real R 4.3.3 with sf 1.0.15: this isn’t a bug in this project, it’s documented sf behavior (see issues #1985 and #1771 on r-spatial/sf). Forcing sf_use_s2(FALSE) routes the call through GEOS, which works correctly here; it’s turned back on right after, because other operations (distances, areas) on geographic coordinates benefit from S2. shapely in Python doesn’t have this problem because it has no alternative S2 engine: it always goes through GEOS.

Repair (optional)

The diagnosis tells you what’s wrong. Repair changes the data — make_valid()/st_make_valid() rebuild the geometry into an equivalent, valid form. Requires having run the diagnosis above at least once: it reuses exactly the same data just diagnosed (gdf in Python, data in R stay in the session between one cell and the next, like in a notebook) — no new reading of the file.

The table and the report above update themselves — the valid_before/valid_after columns automatically appear next to the diagnosis ones.

What about relationships between geometries?

A geometry can be perfectly valid on its own and still be wrong in relation to other geometries — two valid polygons overlapping when they shouldn’t, a gap between areas that should touch. That’s a different problem: topology. It’s covered in Topology Errors in a GeoJSON.