Source: https://gometry.monicz.dev/guide/errors/

# Errors & exceptions

Catch errors by the action your application can take: fix an input type, correct
a value, reduce generated work, or handle a representation or resource failure.
Gometry's exception classes are available directly from `gometry`, such as
[`gm.CRSMismatchError`](https://gometry.monicz.dev/api/errors/#gometry.CRSMismatchError "CRSMismatchError").

```text
ValueError
└── GeometryError              invalid geometry, parameter value, or metadata
    ├── InvalidGeometryError        a geometry violates a structural or numeric rule
    ├── CRSError             a CRS could not be created, identified, exported, or used
    │   ├── CRSMismatchError operands carry incompatible CRS / coordinate-epoch metadata
    │   └── TransformError   a coordinate transform could not be built or failed to run
    └── ParseError           serialized input (WKT, WKB, GeoJSON, cell ids/tokens) is malformed

TypeError
└── GeometryTypeError        wrong geometry kind for the operation

RuntimeError
└── ResourceLimitError       output or computation budget exhausted
```

Grid-cell surfaces follow the same split as everything else: an out-of-range
`resolution`/`level`/`precision`/`zoom` is a plain `GeometryError` (a bad
parameter value), while an invalid cell id, token, or quadkey is a
[`ParseError`](https://gometry.monicz.dev/api/errors/#gometry.ParseError "ParseError") whose `.format` tag names the system (`'h3'`, `'s2'`,
`'geohash'`, `'tile'`, `'quadkey'`); codec tags are lowercase machine keys.

## Built-in exception compatibility

1. **Invalid values are `ValueError`s.** `GeometryError` and its subclasses
   identify bad data or parameter values; specific classes preserve recovery detail.
2. **Python protocol semantics stay builtin.** A non-number where a number is
   required is a plain `TypeError` (floats *and* integers); an out-of-range
   `arr[i]` is an `IndexError`; an exhausted iterator is `StopIteration`.
   Those protocol failures are not rewrapped.

[`GeometryTypeError`](https://gometry.monicz.dev/api/errors/#gometry.GeometryTypeError "GeometryTypeError") subclasses only `TypeError`:
handing [`line_substring`](https://gometry.monicz.dev/api/geometry/geometry/#gometry.Geometry.line_substring "line_substring") a
[`Polygon`](https://gometry.monicz.dev/api/geometry/geometry-types/#gometry.Polygon "Polygon") requires a different geometry kind, not a repaired
polygon. It is not caught by `except ValueError` or `except GeometryError`.

[`ResourceLimitError`](https://gometry.monicz.dev/api/errors/#gometry.ResourceLimitError "ResourceLimitError") subclasses `RuntimeError`.
It means a bounded computation stopped; it does not establish that the input is
invalid or that no result exists. `OverflowError` means a size or result cannot
be represented, including certified binary64 geometry output. Operating-system
failures remain `OSError`; Python allocation failures remain `MemoryError`.
Internal computation consistency failures use `RuntimeError`, not a bad-input
exception.

## Catching errors

The most specific exception class identifies the recovery strategy:

| I want to… | catch |
| --- | --- |
| reject a malformed scalar or batch ingest | [`ParseError`](https://gometry.monicz.dev/api/errors/#gometry.ParseError "ParseError") |
| reproject and retry on frame disagreements | [`CRSMismatchError`](https://gometry.monicz.dev/api/errors/#gometry.CRSMismatchError "CRSMismatchError") |
| fall back when a transform cannot be built or run | [`TransformError`](https://gometry.monicz.dev/api/errors/#gometry.TransformError "TransformError") |
| handle any CRS trouble in one place | [`CRSError`](https://gometry.monicz.dev/api/errors/#gometry.CRSError "CRSError") |
| reject invalid geometry, metadata, or parameter values | [`GeometryError`](https://gometry.monicz.dev/api/errors/#gometry.GeometryError "GeometryError") |
| treat a wrong geometry kind as a type bug | `TypeError` *(or [`GeometryTypeError`](https://gometry.monicz.dev/api/errors/#gometry.GeometryTypeError "GeometryTypeError"))* |
| treat any bad value like the stdlib does | `ValueError` |
| reduce generated output or work after a budget refusal | [`ResourceLimitError`](https://gometry.monicz.dev/api/errors/#gometry.ResourceLimitError "ResourceLimitError") |
| handle an unrepresentable result or size | `OverflowError` |

```python
import gometry as gm

square = gm.box(0, 0, 2, 2)
tagged = gm.Point(1, 1, crs=4326)

try:
    gm.contains(square, tagged)
except gm.CRSMismatchError as e:
    print(type(e).__name__, '→', e)
```

```text
CRSMismatchError → contains requires matching CRS metadata: both operands must share one CRS, or both be CRS-free; got None and "EPSG:4326"; use with_crs(...) or to_crs(...) to align them
```

A batch parser is fail-fast: one malformed row rejects the whole batch and the
exception identifies the row. If partial recovery is an explicit application
policy, parse rows individually and catch `ParseError`:

```python
import gometry as gm

rows = ['POINT (1 2)', 'POINT (oops)', 'LINESTRING (0 0, 1 1)']
parsed = []
for row in rows:
    try:
        parsed.append(gm.from_wkt(row))
    except gm.ParseError:
        pass
print(len(parsed), 'of', len(rows), 'rows parsed')
```

```text
2 of 3 rows parsed
```

```python
import gometry as gm

polygon = gm.box(0, 0, 1, 1)
for catch in (TypeError, gm.GeometryTypeError):
    try:
        polygon.line_interpolate(0.5)
    except catch as e:
        print(f'caught as {catch.__name__}: {type(e).__name__}')
```

```text
caught as TypeError: GeometryTypeError
caught as GeometryTypeError: GeometryTypeError
```

## Troubleshooting common errors

| You see | It means | Fix |
| --- | --- | --- |
| `CRSMismatchError: ... CRS-free vs "EPSG:4326"` | one operand carries a CRS and the other doesn't (or they differ) | tag the bare one with `with_crs(...)`, or reproject with `to_crs(...)` — gometry never coerces frames |
| `CRSError: with_crs would re-tag CRS ... without moving coordinates` | you asked to *relabel* a geometry that already has a CRS | `to_crs(...)` to reproject; `with_crs(..., overwrite=True)` only if the original tag was wrong |
| `CRSError: ... epoch requires a CRS` | a coordinate epoch is meaningless without a frame | set the CRS first (or together: `Point(..., crs=..., epoch=...)`) |
| `InvalidGeometryError: ... cannot carry Z/M` (`to_geojson` on M or `to_polyline` on Z/M) | the target format has no slot for those ordinates | use WKB/WKT/GeoArrow, or explicitly clear dimensions with `with_coordinates(m=None)` / `force_2d()` when loss is intended |
| [`ParseError`](https://gometry.monicz.dev/api/errors/#gometry.ParseError "ParseError") with `.format` set | a serialized input (WKT/WKB/GeoJSON/GeoArrow/GeoParquet/pickle/cell id/quadkey) is malformed | check `e.format` for which codec rejected it; a batch fails as a unit and attaches the failing row as a note |
| `GeometryError: values contains missing geometries` | a list/sequence was used where the operation requires dense geometry values | call [`drop_missing()`](https://gometry.monicz.dev/api/geometry/geometryarray/#gometry.GeometryArray.drop_missing "drop_missing") first or [`fill_missing(...)`](https://gometry.monicz.dev/api/geometry/geometryarray/#gometry.GeometryArray.fill_missing "fill_missing") with an explicit replacement |
| `GeometryError: ... must be between ... got ...` | a parameter value is out of its documented range | the message names the kwarg and the valid range |
| `OverflowError: <operation> cannot be represented in binary64` | no adjacent-coordinate assignment passed the exact output certificate | simplify or snap near-coincident input boundaries when the application allows it, or split the operation |
| `ResourceLimitError: <operation> could not certify ... within its search budget` | the bounded search stopped before certifying an assignment; this does not prove that no assignment exists | simplify or snap near-coincident input boundaries when the application allows it, or split the operation |
| `GeometryError: unknown ... did you mean ...?` | a token typo (`'mitter'` vs `'miter'`, …) | take the suggestion; tokens are also `Literal`-typed, so a type checker catches this before runtime |
| `InvalidGeometryError: invalid longitude/latitude (...)` | geographic input outside the CRS-native longitude period or latitude/pole domain | check axis order — gometry is always `(x, y)`; under a geographic CRS that is `(lon, lat)` in native angular units; [`swap_xy()`](https://gometry.monicz.dev/api/geometry/geometry/#gometry.Geometry.swap_xy "swap_xy") repairs latitude-first data |
| `ambiguous_full_turn_ring` in a geographic validation report | an unmarked ring winds once around the longitude period but its latitude span crosses the equator or lies entirely on it | close the boundary explicitly through a pole or split it into unambiguous rings |
| metric looks unexpectedly large or small | raw angular coordinates were mistaken for a metric unit | let the CRS drive (no `unit=`), and check the geometry carries the intended CRS |

## Error attributes

Operation-raised errors carry operation values as attributes, so handlers act on
data instead of parsing messages. Gometry classes provide `None` defaults when
an attribute does not apply. Built-in `OverflowError` instances carry `code` and
`operation` only for certified output refusals; use `getattr(error, 'code', None)`
when handling other overflow sources too.

| Attribute | Classes | Meaning |
| --- | --- | --- |
| [`field`](https://gometry.monicz.dev/api/errors/#gometry.CRSMismatchError.field "field instance-attribute") | [`CRSMismatchError`](https://gometry.monicz.dev/api/errors/#gometry.CRSMismatchError "CRSMismatchError") | Which metadata disagreed: `'crs'` or `'epoch'` |
| [`left`](https://gometry.monicz.dev/api/errors/#gometry.CRSMismatchError.left "left instance-attribute") / [`right`](https://gometry.monicz.dev/api/errors/#gometry.CRSMismatchError.right "right instance-attribute") | `CRSMismatchError` | Raw conflicting values (CRS identifiers or epoch floats; not quoted presentation strings) |
| [`index`](https://gometry.monicz.dev/api/errors/#gometry.CRSMismatchError.index "index instance-attribute") | `CRSMismatchError` | Collection item that disagreed (when applicable) |
| [`format`](https://gometry.monicz.dev/api/errors/#gometry.ParseError.format "format instance-attribute") | [`ParseError`](https://gometry.monicz.dev/api/errors/#gometry.ParseError "ParseError") | Lowercase space-free codec key, including `'pickle'` alongside `'wkt'`, `'wkb'`, `'geojson'`, `'geoarrow'`, `'geoparquet'`, grid codecs, and geocoders |
| [`position`](https://gometry.monicz.dev/api/errors/#gometry.ParseError.position "position instance-attribute") | `ParseError` | WKT/EWKT reports the zero-based UTF-8 byte offset where parsing detected the error, including an EWKT prefix; WKB reports its zero-based binary byte offset; other codecs report `None` when unavailable |
| [`param`](https://gometry.monicz.dev/api/errors/#gometry.GeometryError.param "param instance-attribute") / [`value`](https://gometry.monicz.dev/api/errors/#gometry.GeometryError.value "value instance-attribute") | [`GeometryError`](https://gometry.monicz.dev/api/errors/#gometry.GeometryError "GeometryError") (invalid values) | Offending keyword and value |
| [`parameter`](https://gometry.monicz.dev/api/errors/#gometry.ResourceLimitError.parameter "parameter instance-attribute") / [`produced`](https://gometry.monicz.dev/api/errors/#gometry.ResourceLimitError.produced "produced instance-attribute") / [`limit`](https://gometry.monicz.dev/api/errors/#gometry.ResourceLimitError.limit "limit instance-attribute") | bounded-output `ResourceLimitError` | Controlling parameter, prospective count (or proven lower bound), and configured limit |
| [`code`](https://gometry.monicz.dev/api/errors/#gometry.ResourceLimitError.code "code instance-attribute") | `ResourceLimitError` | `'output_limit'` or `'work_limit'`; `None` for hand-built errors |
| `code` / `operation` | certified-output `OverflowError` | `'output_unrepresentable'` and the operation that could not publish its result |
| [`expected`](https://gometry.monicz.dev/api/errors/#gometry.GeometryTypeError.expected "expected instance-attribute") / [`got`](https://gometry.monicz.dev/api/errors/#gometry.GeometryTypeError.got "got instance-attribute") | [`GeometryTypeError`](https://gometry.monicz.dev/api/errors/#gometry.GeometryTypeError "GeometryTypeError") | Required and received geometry kinds |
| [`source`](https://gometry.monicz.dev/api/errors/#gometry.TransformError.source "source instance-attribute") / [`target`](https://gometry.monicz.dev/api/errors/#gometry.TransformError.target "target instance-attribute") | [`TransformError`](https://gometry.monicz.dev/api/errors/#gometry.TransformError "TransformError") | Source and target CRS of a failed transform |
| [`operation`](https://gometry.monicz.dev/api/errors/#gometry.ResourceLimitError.operation "operation instance-attribute") / [`operation`](https://gometry.monicz.dev/api/errors/#gometry.InvalidGeometryError.operation "operation instance-attribute") | `ResourceLimitError`; `InvalidGeometryError` (empty sequence or invalid coverage) | Operation associated with the failure |
| [`row`](https://gometry.monicz.dev/api/errors/#gometry.InvalidGeometryError.row "row instance-attribute") / [`path`](https://gometry.monicz.dev/api/errors/#gometry.InvalidGeometryError.path "path instance-attribute") | [`InvalidGeometryError`](https://gometry.monicz.dev/api/errors/#gometry.InvalidGeometryError "InvalidGeometryError") (require) | Failing array row and structural path |
| [`code`](https://gometry.monicz.dev/api/errors/#gometry.InvalidGeometryError.code "code instance-attribute") / [`detail`](https://gometry.monicz.dev/api/errors/#gometry.InvalidGeometryError.detail "detail instance-attribute") | [`InvalidGeometryError`](https://gometry.monicz.dev/api/errors/#gometry.InvalidGeometryError "InvalidGeometryError") (require) | Open-string validity issue code and human-readable issue detail |
| [`location`](https://gometry.monicz.dev/api/errors/#gometry.InvalidGeometryError.location "location instance-attribute") | [`InvalidGeometryError`](https://gometry.monicz.dev/api/errors/#gometry.InvalidGeometryError "InvalidGeometryError") (require) | Coordinate witness for the validity issue; quotient-topology issues choose a canonical coordinate of their contact set deterministically by minimum latitude then longitude |
| [`crs`](https://gometry.monicz.dev/api/errors/#gometry.CRSError.crs "crs instance-attribute") | [`CRSError`](https://gometry.monicz.dev/api/errors/#gometry.CRSError "CRSError") | CRS involved in a unit/authority mismatch |

```python
import gometry as gm

try:
    gm.contains(gm.box(0, 0, 1, 1), gm.Point(1, 1, crs=4326))
except gm.CRSMismatchError as e:
    print('field:', e.field, '| left:', e.left, '| right:', e.right)

try:
    gm.from_wkt('POINT (oops)')
except gm.ParseError as e:
    print('format:', e.format)
```

```text
field: crs | left: None | right: EPSG:4326
format: wkt
```

## Rows in array errors

A per-element failure in an array operation keeps its class and message —
so `except ParseError` still catches — and names the failing row as a
[PEP 678](https://peps.python.org/pep-0678/) note that tracebacks display:

```python
import gometry as gm

try:
    gm.from_wkt(['POINT (1 2)', 'POINT (oops)'])
except gm.ParseError as e:
    print(e)
    print(e.__notes__[0])
```

```text
invalid WKT: coordinate is missing y
while processing array element 1
```

Branch on exception classes, attributes, and `.code` values rather than
parsing error messages.

## Pickling

Exceptions cross process boundaries intact — `multiprocessing`, `dask`, and
`concurrent.futures` re-raise them as the same class with the same message:

```python
import pickle

import gometry as gm

error = gm.GeometryError('h3 resolution must be between 0 and 15, got 99')
clone = pickle.loads(pickle.dumps(error))
print(type(clone).__name__, '|', clone)
```

```text
GeometryError | h3 resolution must be between 0 and 15, got 99
```

## See also

- [Validation & repair](https://gometry.monicz.dev/guide/validation/) — turning invalid geometry into a report, then a fix.
- [CRS, units & measurement](https://gometry.monicz.dev/guide/crs/) — the frame rules behind [`CRSMismatchError`](https://gometry.monicz.dev/api/errors/#gometry.CRSMismatchError "CRSMismatchError").
- [Security & untrusted input](https://gometry.monicz.dev/about/security/) — catching [`ParseError`](https://gometry.monicz.dev/api/errors/#gometry.ParseError "ParseError") at trust boundaries.
- [API: errors](https://gometry.monicz.dev/api/errors/) — the full class reference.
