Empty Geometry in GeoPackage¶
A GeoPackage containing rows with empty geometries (WKB EMPTY representation) to test how loaders handle the distinction between NULL geometry and EMPTY geometry. In GeoPackage/SQLite, NULL means "no geometry value" while EMPTY means "a geometry that contains no coordinates". This case exposes loaders that conflate NULL and EMPTY or fail to handle EMPTY geometries correctly.
| Property | Value |
|---|---|
| Case ID | empty_geometry_gpkg |
| Category | vector |
| Format | GPKG |
| Geometry type | Point |
| CRS | EPSG:4326 |
| Location | Central Europe (synthetic) — 10.00°E, 50.00°N → 11.00°E, 51.00°N |
| Test tier | unit |
| Size class | tiny |
| Storage class | bundled |
| Redistributable | yes |
| Loader | geopandas |
| Status | validated |
Use this case¶
import pytest
@pytest.mark.geocase_case("empty_geometry_gpkg")
def test_empty_geometry_gpkg(geocase_case) -> None:
data = geocase_case.load()
assert data is not None
Use GeoCase in your tests¶
Install the complete set of vector, raster, and NetCDF dependencies:
What this case checks¶
Expose loaders that incorrectly handle EMPTY geometries in GeoPackage format. Detect confusion between SQL NULL and WKB EMPTY geometry representations. Test filtering and query behavior with empty geometries.
Risk types covered¶
Expected behavior¶
| Assertion | Expected |
|---|---|
expect_loadable |
yes |
expect_valid_geometry |
no |
expect_crs |
yes |
expected_epsg |
4326 |
expected_geometry_types |
Point |
Known consumer divergences¶
Disagreements already investigated on this case. If your reader reproduces one of these, it is catalogued — not a new finding.
pyogrio — pyogrio >=0.11, GDAL 3.12-3.13 (originates in GDAL)
Under a spatial filter (bbox= or mask=), the Arrow path (use_arrow=True) returns the NULL-geometry row that the numpy path and GDAL's own ogrinfo -spat both exclude -- 3 rows against 2. Traced to GPKG's GetArrowStream fast path; only GPKG diverges among GeoJSON, Shapefile and SQLite. A NULL geometry intersects nothing, so the numpy path is the correct one.
Upstream: https://github.com/farzinashouri/geocase/blob/main/docs/geocase_validate/gdal-issue-draft.md
lonboard — lonboard 0.11, geoarrow-pyarrow 0.5
from_geopandas emits no Arrow validity bitmap, so a NULL geometry is indistinguishable from a geometry with NaN coordinates. geopandas' own Arrow export, which does set the bitmap, is the reference.
Notes¶
Purpose¶
This case tests the distinction between NULL and EMPTY geometries in GeoPackage format. This is a critical edge case that many loaders handle incorrectly.
Problem Demonstrated¶
GeoPackage (SQLite-based) distinguishes two "missing geometry" states:
| State | SQL Value | WKB Representation | Meaning |
|---|---|---|---|
| NULL | NULL |
No value stored | "No geometry recorded" |
| EMPTY | WKB blob | POINT EMPTY (7 bytes) |
"A point with no coordinates" |
Why This Matters¶
Different operations behave differently with NULL vs EMPTY:
| Operation | NULL Geometry | EMPTY Geometry |
|---|---|---|
IS NULL check |
TRUE | FALSE |
| Spatial index | Not indexed | May be indexed |
ST_IsEmpty() |
NULL (or error) | TRUE |
| Bounds calculation | Excluded | Zero-area bounds |
| Export to GeoJSON | null or omitted |
{"type": "Point", "coordinates": []} |
Test Data¶
This GeoPackage contains 4 rows:
| Row | ID | Geometry | State |
|---|---|---|---|
| 1 | valid_1 | POINT(10 50) | Valid geometry |
| 2 | valid_2 | POINT(11 51) | Valid geometry |
| 3 | null_row | SQL NULL | NULL geometry |
| 4 | empty_row | POINT EMPTY | EMPTY geometry |
Expected Behavior¶
- Loaders should successfully read all 4 rows
- NULL and EMPTY geometries should be distinguishable
- Spatial operations should handle both states correctly
- Export should preserve the NULL/EMPTY distinction
Format-Specific Behavior¶
| Format | NULL Support | EMPTY Support | Notes |
|---|---|---|---|
| GeoPackage | Yes (SQL NULL) | Yes (WKB EMPTY) | Full distinction |
| Shapefile | No (all NULL) | Sort of | No true NULL, empty = deleted |
| GeoJSON | Yes (null) |
Yes ([] coords) |
Spec allows both |
| WKT | No | Yes (POINT EMPTY) |
NULL not representable |
This case is GeoPackage-specific because of SQLite's explicit NULL handling.
Required capabilities¶
loadgeometry-validationnull-handling
Files¶
- Primary:
empty_geom.gpkg - Notes:
notes.md
Source and license¶
- Source: geocase-curated
- License: MIT
Tags¶
empty format_specific geometry_special geopackage null_handling vector
Related cases¶
- Empty Polygon --
empty_polygon - Format-Limited KML Case --
format_limited_kml_case - First NULL After 10,000 Non-NULL Values (GeoPackage) --
null_after_batch_boundary_gpkg - GeoJSON Precision Loss Roundtrip --
precision_loss_geojson_roundtrip - Shapefile Legacy DBF Encoding --
shapefile_encoding_legacy