elastic/elasticsearch · error · ParseException
maximum nested depth of 1000 exceeded
Error message
maximum nested depth of 1000 exceeded
What it means
Thrown by WellKnownText.parseGeometryCollection when the recursion depth exceeds MAX_NESTED_DEPTH (1000). Each nested GEOMETRYCOLLECTION increments the depth counter passed to parseGeometry; this guards the recursive descent against unbounded input.
Source
Thrown at libs/geo/src/main/java/org/elasticsearch/geometry/utils/WellKnownText.java:482
checkZorMAttribute(isExplicitlySpecifiesZorM, geometry.hasZ());
return geometry;
}
static void checkZorMAttribute(boolean isExplicitlySpecifiesZorM, boolean hasZ) {
if (isExplicitlySpecifiesZorM && hasZ == false) {
throw new IllegalArgumentException(
"When specifying 'Z' or 'M', coordinates must include three values. Only two coordinates were provided"
);
}
}
private static GeometryCollection<Geometry> parseGeometryCollection(StreamTokenizer stream, boolean coerce, int depth)
throws IOException, ParseException {
if (nextEmptyOrOpen(stream).equals(EMPTY)) {
return GeometryCollection.EMPTY;
}
if (depth > MAX_NESTED_DEPTH) {
throw new ParseException("maximum nested depth of " + MAX_NESTED_DEPTH + " exceeded", stream.lineno());
}
List<Geometry> shapes = new ArrayList<>();
shapes.add(parseGeometry(stream, coerce, depth));
while (nextCloserOrComma(stream).equals(COMMA)) {
shapes.add(parseGeometry(stream, coerce, depth));
}
return new GeometryCollection<>(shapes);
}
private static Point parsePoint(StreamTokenizer stream) throws IOException, ParseException {
if (nextEmptyOrOpen(stream).equals(EMPTY)) {
return Point.EMPTY;
}
double lon = nextNumber(stream);
double lat = nextNumber(stream);
Point pt;
if (isNumberNext(stream)) {
pt = new Point(lon, lat, nextNumber(stream));View on GitHub (pinned to db6a809a66)
Solutions
- Flatten or reduce the nesting depth of the input geometry collection to <= 1000 levels.
- If the deep nesting is legitimate (unlikely), pre-validate by counting GEOMETRYCOLLECTION tokens and reject upstream with a clearer message.
- Sanitize untrusted WKT before parsing to cap collection nesting.
Example fix
// before: deeply nested collection from untrusted source
String wkt = maliciousInput; // GEOMETRYCOLLECTION nested 5000 deep
Geometry g = WellKnownText.fromWKT(wkt);
// after: cap nesting before parsing
long depth = wkt.chars().filter(c -> c == '(').count();
if (depth > 1000) {
throw new IllegalArgumentException("WKT nesting too deep: " + depth);
}
Geometry g = WellKnownText.fromWKT(wkt); Defensive patterns
Strategy: validation
Validate before calling
static void checkNestingDepth(String wkt) {
int depth = 0, max = 0;
for (int i = 0; i < wkt.length(); i++) {
char c = wkt.charAt(i);
if (c == '(') { depth++; max = Math.max(max, depth); }
else if (c == ')') depth--;
}
if (max > 1000) {
throw new IllegalArgumentException("WKT nesting depth " + max + " exceeds limit 1000");
}
} Try / catch
try {
Geometry g = WellKnownText.fromWKT(wkt);
} catch (java.text.ParseException e) {
if (e.getMessage().contains("nested depth")) {
// reject input as too deeply nested
}
throw e;
} Prevention
- Cap collection nesting for untrusted WKT before parsing.
- Count open-paren depth as a cheap pre-validation.
- Flatten generated collections that wrap redundantly.
When it happens
Trigger: Parsing a WKT string with more than 1000 levels of nested GEOMETRYCOLLECTION, e.g. "GEOMETRYCOLLECTION (GEOMETRYCOLLECTION (GEOMETRYCOLLECTION ( ... )))" deeper than 1000. Also reachable if the depth parameter is misused by a caller invoking the package-private parseGeometry directly with a large starting depth.
Common situations: Adversarial or fuzzed input designed to cause stack exhaustion; generated test fixtures with runaway nesting; a serialization bug that emits redundant wrapping collections.
Related errors
- When specifying 'Z' or 'M', coordinates must include three v
- coordinate dimensions do not match: {}
- expected word but found: {}
- invalid number found: {}
- expected number but found: {}
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/1eca00903fd78336.
Report an issue: GitHub.