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

  1. Flatten or reduce the nesting depth of the input geometry collection to <= 1000 levels.
  2. If the deep nesting is legitimate (unlikely), pre-validate by counting GEOMETRYCOLLECTION tokens and reject upstream with a clearer message.
  3. 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

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


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/1eca00903fd78336. Report an issue: GitHub.