{"record":{"id":"eb4aa7e6e3f03350","repo":"elastic/elasticsearch","slug":"unknown-geometry-type-eb4aa7","errorCode":null,"errorMessage":"Unknown geometry type: {}","messagePattern":"Unknown geometry type: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"libs/geo/src/main/java/org/elasticsearch/geometry/utils/WellKnownBinary.java","lineNumber":674,"sourceCode":"    private static Geometry parseGeometry(ByteBuffer byteBuffer, boolean coerce) {\n        byteBuffer.order(byteBuffer.get() == 0 ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN);\n        final int type = byteBuffer.getInt();\n        return switch (type) {\n            case 1 -> parsePoint(byteBuffer, false);\n            case 1001 -> parsePoint(byteBuffer, true);\n            case 2 -> parseLine(byteBuffer, false);\n            case 1002 -> parseLine(byteBuffer, true);\n            case 3 -> parsePolygon(byteBuffer, false, coerce);\n            case 1003 -> parsePolygon(byteBuffer, true, coerce);\n            case 4, 1004 -> parseMultiPoint(byteBuffer);\n            case 5, 1005 -> parseMultiLine(byteBuffer);\n            case 6, 1006 -> parseMultiPolygon(byteBuffer, coerce);\n            case 7, 1007 -> parseGeometryCollection(byteBuffer, coerce);\n            case 17 -> parseCircle(byteBuffer, false);\n            case 1017 -> parseCircle(byteBuffer, true);\n            case 18 -> parseBBox(byteBuffer, false);\n            case 1018 -> parseBBox(byteBuffer, true);\n            default -> throw new IllegalArgumentException(\"Unknown geometry type: \" + type);\n        };\n    }\n\n    private static Point parsePoint(ByteBuffer byteBuffer, boolean hasZ) {\n        if (hasZ) {\n            return new Point(byteBuffer.getDouble(), byteBuffer.getDouble(), byteBuffer.getDouble());\n        } else {\n            return new Point(byteBuffer.getDouble(), byteBuffer.getDouble());\n        }\n    }\n\n    private static Line parseLine(ByteBuffer byteBuffer, boolean hasZ) {\n        final int length = byteBuffer.getInt();\n        if (length == 0) {\n            return Line.EMPTY;\n        }\n        final double[] lats = new double[length];\n        final double[] lons = new double[length];","sourceCodeStart":656,"sourceCodeEnd":692,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/geo/src/main/java/org/elasticsearch/geometry/utils/WellKnownBinary.java#L656-L692","documentation":"WellKnownBinary.fromWKB (line 642) parses a WKB byte array via parseGeometry (line 656). After reading byte order and the 4-byte type int (lines 657-658), it switches over the recognized type codes (1-7, 1001-1007, 17/1017, 18/1018). Any other type code hits the default at line 674 and throws IllegalArgumentException. This indicates corrupt, truncated, or non-conforming WKB.","triggerScenarios":"Calling WellKnownBinary.fromWKB(validator, coerce, wkb) with bytes whose type-code int (after the byte-order byte) is outside the recognized set. Caused by: truncated buffer (offset misread so a coordinate is parsed as the type), wrong endianness interpretation, an OGC type this library does not support (e.g. 8=CircularString, 9=CompoundCurve, 15=PolyhedralSurface, 16=Tin), or post-SQL-MM extended codes.","commonSituations":"Ingesting WKB from SQL-MM / PostGIS IWKB / EWKB sources that use unsupported extended geometry types. Bit-rot or truncation in transport/storage. Endianness confusion between producer and consumer. Misaligned offsets when slicing a larger buffer.","solutions":["Verify the WKB came from a producer that emits only OGC types 1-7 (optionally ES 17/18 and the 10xx Z variants); convert unsupported SQL-MM types upstream.","Check buffer length is at least 5 and that the type int is in the supported set before calling fromWKB.","Confirm producer and consumer agree on byte order; if the producer emits EWKB, strip the EWKB header/SRID extension first.","Catch IllegalArgumentException and report the offending type code for diagnosis."],"exampleFix":"// before\nGeometry g = WellKnownBinary.fromWKB(v, false, rawBytes); // throws on type=8 (CircularString)\n\n// after — guard the type code\nint code = ByteBuffer.wrap(rawBytes, 1, 4)\n    .order(rawBytes[0] == 0 ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN).getInt();\nif (Set.of(1,2,3,4,5,6,7,17,18,1001,1002,1003,1004,1005,1006,1007,1017,1018).contains(code) == false) {\n    throw new IllegalArgumentException(\"Unsupported WKB type code: \" + code);\n}\nGeometry g = WellKnownBinary.fromWKB(v, false, rawBytes);","handlingStrategy":"validation","validationCode":"static final Set<Integer> SUPPORTED_WKB_TYPES = Set.of(\n    1,2,3,4,5,6,7,17,18, 1001,1002,1003,1004,1005,1006,1007,1017,1018);\nboolean isSupportedWkbType(byte[] wkb) {\n    if (wkb == null || wkb.length < 5) return false;\n    ByteOrder bo = wkb[0] == 0 ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;\n    int type = ByteBuffer.wrap(wkb, 1, 4).order(bo).getInt();\n    return SUPPORTED_WKB_TYPES.contains(type);\n}","typeGuard":"static Integer readWkbType(byte[] wkb) {\n    if (wkb == null || wkb.length < 5) return null;\n    ByteOrder bo = wkb[0] == 0 ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;\n    return ByteBuffer.wrap(wkb, 1, 4).order(bo).getInt();\n}","tryCatchPattern":"try {\n    return WellKnownBinary.fromWKB(v, coerce, wkb);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Unknown geometry type\")) {\n        // quarantine record; log the offending type code for diagnosis\n    }\n    throw e;\n}","preventionTips":["Verify the producer emits only OGC types 1-7 (and ES 17/18, plus 10xx Z variants).","Strip EWKB headers / SRID extensions before fromWKB.","Confirm producer and consumer agree on byte order.","Validate buffer length >= 5 and type code is in the supported set before parsing."],"tags":["geo","wkb","deserialization","unknown-type","corrupt","elasticsearch"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}