{"record":{"id":"743d97bdd8cccf71","repo":"elastic/elasticsearch","slug":"linear-ring-is-not-supported-by-wkb","errorCode":null,"errorMessage":"Linear ring is not supported by WKB","messagePattern":"Linear ring is not supported by WKB","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"libs/geo/src/main/java/org/elasticsearch/geometry/utils/WellKnownBinary.java","lineNumber":180,"sourceCode":"                if (rectangle.isEmpty()) {\n                    throw new IllegalArgumentException(\"Empty \" + rectangle.type() + \" cannot be represented in WKB\");\n                }\n                writeInt(out, scratch, rectangle.hasZ() ? 1018 : 18);\n                // minX, maxX, maxY, minY\n                writeDouble(out, scratch, rectangle.getMinX());\n                writeDouble(out, scratch, rectangle.getMaxX());\n                writeDouble(out, scratch, rectangle.getMaxY());\n                writeDouble(out, scratch, rectangle.getMinY());\n                if (rectangle.hasZ()) {\n                    writeDouble(out, scratch, rectangle.getMinZ());\n                    writeDouble(out, scratch, rectangle.getMaxZ());\n                }\n                return null;\n            }\n\n            @Override\n            public Void visit(LinearRing ring) {\n                throw new IllegalArgumentException(\"Linear ring is not supported by WKB\");\n            }\n\n            private void visitLinearRing(LinearRing ring) {\n                writeInt(out, scratch, ring.length());\n                for (int i = 0; i < ring.length(); i++) {\n                    writeDouble(out, scratch, ring.getX(i));\n                    writeDouble(out, scratch, ring.getY(i));\n                    if (ring.hasZ()) {\n                        writeDouble(out, scratch, ring.getZ(i));\n                    }\n                }\n            }\n        });\n    }\n\n    private static void writeInt(ByteArrayOutputStream out, ByteBuffer scratch, int i) {\n        scratch.clear();\n        scratch.putInt(i);","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/geo/src/main/java/org/elasticsearch/geometry/utils/WellKnownBinary.java#L162-L198","documentation":"WellKnownBinary.toWKB's public visitor has a visit(LinearRing) override (line 179) that unconditionally throws IllegalArgumentException. LinearRing is intentionally not a standalone WKB type — it only exists as the structural innards of a Polygon. The private visitLinearRing (line 183) is used internally by the Polygon visitor to write ring data; a bare LinearRing reaching the top-level visitor is a caller bug.","triggerScenarios":"Calling WellKnownBinary.toWKB(linearRing, byteOrder) where the argument is a standalone LinearRing (not wrapped in a Polygon). Constructing a Polygon manually but accidentally passing its shell ring (polygon.getPolygon()) instead of the polygon itself to toWKB.","commonSituations":"Custom geometry builders that assemble LinearRing shells/holes and then serialize the ring rather than the containing Polygon. Refactoring that extracts ring handling and accidentally routes a ring into the top-level serializer. Misuse of the public toWKB API with internally-typed objects.","solutions":["Wrap the LinearRing in a Polygon before serializing: new Polygon(linearRing) or new Polygon(shell, holes).","Ensure you pass the Polygon (which contains the ring) to toWKB, never a bare LinearRing.","Add an instanceof guard before toWKB to reject LinearRing inputs at the API boundary."],"exampleFix":"// before\nLinearRing shell = new LinearRing(lons, lats);\nbyte[] wkb = WellKnownBinary.toWKB(shell, ByteOrder.LITTLE_ENDIAN); // throws\n\n// after\nPolygon polygon = new Polygon(shell);\nbyte[] wkb = WellKnownBinary.toWKB(polygon, ByteOrder.LITTLE_ENDIAN);","handlingStrategy":"type-guard","validationCode":"Geometry ensureNotBareRing(Geometry g) {\n    if (g instanceof LinearRing r) return new Polygon(r);\n    return g;\n}","typeGuard":"static boolean isBareLinearRing(Geometry g) { return g instanceof LinearRing; }","tryCatchPattern":"try {\n    return WellKnownBinary.toWKB(g, bo);\n} catch (IllegalArgumentException e) {\n    if (g instanceof LinearRing r) return WellKnownBinary.toWKB(new Polygon(r), bo);\n    throw e;\n}","preventionTips":["Never pass a bare LinearRing to toWKB; always wrap in a Polygon.","Add an instanceof LinearRing guard at the API boundary of your serialization helper.","Treat LinearRing as a structural, internal-only type in your data flow."],"tags":["geo","wkb","serialization","linear-ring","polygon","elasticsearch"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}