{"record":{"id":"5a6a7b603e97f9ac","repo":"elastic/elasticsearch","slug":"empty-point-cannot-be-represented-in-wkb","errorCode":null,"errorMessage":"Empty POINT cannot be represented in WKB","messagePattern":"Empty POINT cannot be represented in WKB","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"libs/geo/src/main/java/org/elasticsearch/geometry/utils/WellKnownBinary.java","lineNumber":282,"sourceCode":"            case \"multilinestring\" -> writeWKBMultiLineString(stream, out, scratch, explicitZ, validator);\n            case \"polygon\" -> writeWKBPolygon(stream, out, scratch, coerce, explicitZ, validator);\n            case \"multipolygon\" -> writeWKBMultiPolygon(stream, out, scratch, coerce, explicitZ, validator);\n            case \"geometrycollection\" -> writeWKBGeometryCollection(stream, out, scratch, coerce, depth, explicitZ, validator);\n            case \"circle\" -> writeWKBCircle(stream, out, scratch, explicitZ, validator);\n            case \"bbox\" -> writeWKBBBox(stream, out, scratch, explicitZ, validator);\n            default -> throw new ParseException(\"Unknown geometry type: \" + type, stream.lineno());\n        }\n    }\n\n    private static void writeWKBPoint(\n        StreamTokenizer stream,\n        ByteArrayOutputStream out,\n        ByteBuffer scratch,\n        boolean explicitZ,\n        GeometryValidator validator\n    ) throws IOException, ParseException {\n        if (WellKnownText.nextEmptyOrOpen(stream).equals(WellKnownText.EMPTY)) {\n            throw new IllegalArgumentException(\"Empty POINT cannot be represented in WKB\");\n        }\n        double x = WellKnownText.nextNumber(stream);\n        double y = WellKnownText.nextNumber(stream);\n        double z = Double.NaN;\n        if (WellKnownText.isNumberNext(stream)) {\n            z = WellKnownText.nextNumber(stream);\n        }\n        WellKnownText.nextCloser(stream);\n        WellKnownText.checkZorMAttribute(explicitZ, Double.isNaN(z) == false);\n        validator.validateCoordinate(x, y, z);\n        boolean hasZ = Double.isNaN(z) == false;\n        writeInt(out, scratch, hasZ ? 1001 : 1);\n        writeDouble(out, scratch, x);\n        writeDouble(out, scratch, y);\n        if (hasZ) {\n            writeDouble(out, scratch, z);\n        }\n    }","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/geo/src/main/java/org/elasticsearch/geometry/utils/WellKnownBinary.java#L264-L300","documentation":"writeWKBPoint (line 274) is the WKT-to-WKB direct converter for the POINT type. After reading the type word, it consumes the next token via nextEmptyOrOpen (line 281); if that token is 'EMPTY', it throws IllegalArgumentException because, per the toWKB rule (error 562), WKB cannot encode an empty Point. This is the WKT-input variant of the same format limitation.","triggerScenarios":"Calling WellKnownBinary.fromWKT(\"POINT EMPTY\", byteOrder, coerce[, validator]). The exact trigger is the literal WKT token 'POINT' followed by 'EMPTY' (case-insensitive type, but EMPTY keyword recognized by nextEmptyOrOpen).","commonSituations":"Indexing optional-location fields where the source represents absence as 'POINT EMPTY' in WKT. Round-tripping data that used WKT's empty-point syntax. Ingest pipelines that pass through user-supplied WKT without normalizing empty points.","solutions":["Detect and skip 'POINT EMPTY' (case-insensitive, trimmed) before calling fromWKT, treating it as absent data.","Normalize empty points to a concrete coordinate or to a null/absent document upstream.","If you must preserve emptiness, use a format that supports it (WKT for storage, or a sentinel schema field) rather than WKB."],"exampleFix":"// before\nbyte[] wkb = WellKnownBinary.fromWKT(\"POINT EMPTY\", ByteOrder.LITTLE_ENDIAN, false); // throws\n\n// after\nString wkt = wktInput.trim();\nif (wkt.equalsIgnoreCase(\"POINT EMPTY\")) {\n    return null; // or handle absence\n}\nbyte[] wkb = WellKnownBinary.fromWKT(wkt, ByteOrder.LITTLE_ENDIAN, false);","handlingStrategy":"validation","validationCode":"boolean isPointEmpty(String wkt) {\n    return wkt.trim().equalsIgnoreCase(\"POINT EMPTY\");\n}","typeGuard":"// lexical guard — WKT has no object yet\nstatic boolean isEmptyPointWkt(String wkt) {\n    return wkt.trim().equalsIgnoreCase(\"POINT EMPTY\");\n}","tryCatchPattern":"try {\n    return WellKnownBinary.fromWKT(wkt, bo, coerce, v);\n} catch (IllegalArgumentException e) {\n    if (wkt.trim().equalsIgnoreCase(\"POINT EMPTY\")) return null;\n    throw e;\n}","preventionTips":["Normalize 'POINT EMPTY' to absent/null at ingest, before WKB conversion.","Use WKT (not WKB) as the on-disk format if empty points must be preserved.","Apply a shared empty-WKT filter for POINT/CIRCLE/BBOX empties."],"tags":["geo","wkt","wkb","point","empty","elasticsearch"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}