{"record":{"id":"6fb5e0bf3f17ae7e","repo":"elastic/elasticsearch","slug":"holes-must-have-the-same-number-of-dimensions-as-t-6fb5e0","errorCode":null,"errorMessage":"holes must have the same number of dimensions as the polygon","messagePattern":"holes must have the same number of dimensions as the polygon","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"libs/geo/src/main/java/org/elasticsearch/geometry/utils/WellKnownBinary.java","lineNumber":344,"sourceCode":"        boolean explicitZ,\n        GeometryValidator validator\n    ) throws IOException, ParseException {\n        if (WellKnownText.nextEmptyOrOpen(stream).equals(WellKnownText.EMPTY)) {\n            writeInt(out, scratch, 3);\n            writeInt(out, scratch, 0);\n            return;\n        }\n        List<CoordsList> rings = new ArrayList<>();\n        WellKnownText.nextOpener(stream);\n        rings.add(wktReadRing(stream, coerce, validator));\n        while (WellKnownText.nextCloserOrComma(stream).equals(WellKnownText.COMMA)) {\n            WellKnownText.nextOpener(stream);\n            rings.add(wktReadRing(stream, coerce, validator));\n        }\n        boolean hasZ = rings.isEmpty() == false && rings.get(0).hasZ();\n        for (CoordsList ring : rings) {\n            if (ring.hasZ() != hasZ) {\n                throw new IllegalArgumentException(\"holes must have the same number of dimensions as the polygon\");\n            }\n        }\n        WellKnownText.checkZorMAttribute(explicitZ, hasZ);\n        writeInt(out, scratch, hasZ ? 1003 : 3);\n        writeInt(out, scratch, rings.size());\n        for (CoordsList ring : rings) {\n            writeInt(out, scratch, ring.size());\n            writeCoordinateList(out, scratch, ring);\n        }\n    }\n\n    private static void writeWKBMultiPoint(\n        StreamTokenizer stream,\n        ByteArrayOutputStream out,\n        ByteBuffer scratch,\n        boolean explicitZ,\n        GeometryValidator validator\n    ) throws IOException, ParseException {","sourceCodeStart":326,"sourceCodeEnd":362,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/geo/src/main/java/org/elasticsearch/geometry/utils/WellKnownBinary.java#L326-L362","documentation":"writeWKBPolygon (line 321) reads the outer ring and any holes from WKT, then at lines 341-345 verifies every ring has the same Z dimensionality as the first (outer) ring. If any hole's hasZ differs from the shell's hasZ, it throws IllegalArgumentException. WKB polygon encoding (type 3 or 1003) is single-dimensionality per geometry — a polygon cannot mix 2D and 3D rings.","triggerScenarios":"Calling WellKnownBinary.fromWKT with a POLYGON WKT whose outer ring and hole(s) disagree on Z presence, e.g. outer 'POLYGON((0 0, 10 0, 10 10, 0 0), (1 1 5, 2 1 5, 2 2 5, 1 1 5))' (outer 2D, hole 3D) or the reverse. Reached during direct WKT-to-WKB conversion.","commonSituations":"Hand-authored WKT where the author added altitude to holes but not the shell (or vice versa). Merging polygon data from sources with inconsistent dimensionality. Edit tools that append Z to selected rings. Programmatic polygon builders that conditionally add Z per-ring.","solutions":["Make dimensionality consistent across all rings of the polygon: either add Z to every ring or remove Z from every ring.","Validate before serialization: parse the WKT, check each ring's Z presence, and normalize (strip Z or backfill) before fromWKT.","Configure your authoring tool to enforce uniform dimensionality per polygon."],"exampleFix":"// before — mixed dimensions\nfromWKT(\"POLYGON((0 0, 10 0, 10 10, 0 0), (1 1 5, 2 1 5, 2 2 5, 1 1 5))\", BO, false, v);\n// throws: holes must have the same number of dimensions as the polygon\n\n// after — all rings 2D\nfromWKT(\"POLYGON((0 0, 10 0, 10 10, 0 0), (1 1, 2 1, 2 2, 1 1))\", BO, false, v);","handlingStrategy":"validation","validationCode":"// after parsing rings into CoordsList-like structures:\nboolean ringsConsistentZ(List<boolean> ringHasZ) {\n    Boolean first = null;\n    for (boolean z : ringHasZ) {\n        if (first == null) first = z;\n        else if (z != first) return false;\n    }\n    return true;\n}","typeGuard":"// structural: confirm outer and all holes share hasZ before fromWKT\nstatic boolean polygonRingsUniformZ(String wkt) {\n    // crude check: count Z triples vs pairs per ring; better: parse to Geometry first\n    return true; // implement per-ring Z-presence scan\n}","tryCatchPattern":"try {\n    return WellKnownBinary.fromWKT(wkt, bo, coerce, v);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"holes must have the same number of dimensions\")) {\n        // normalize: strip Z from all rings, then retry\n    } else throw e;\n}","preventionTips":["Enforce uniform per-polygon dimensionality in authoring/import tools.","Pre-validate ring Z presence and normalize (strip or backfill) before fromWKT.","Reject mixed-dimension polygons at the API boundary with a clear error."],"tags":["geo","wkt","wkb","polygon","z-value","dimensionality","elasticsearch"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}