OtterMind/Chat2DB · info · IllegalArgumentException

EWKB linear ring is not closed

Error message

EWKB linear ring is not closed

What it means

Thrown by PostgreSQLGeometryProcessor.inspectLinearRing when the first and last coordinates of a polygon ring do not match in their first two dimensions (X, Y). Per the OGC SFA specification, linear rings must be closed: the starting point must equal the ending point. This validation compares only the first two ordinates (indices 0 and 1) at lines 247-251. The exception is caught by convertJDBCValueByType at line 80 and the raw hex value is returned gracefully.

Source

Thrown at chat2db-community-server/chat2db-community-plugins/chat2db-community-postgresql/src/main/java/ai/chat2db/plugin/postgresql/value/sub/PostgreSQLGeometryProcessor.java:249

        int coordinateCount = readCount(cursor, byteOrder);
        if (coordinateCount == 1) {
            throw new IllegalArgumentException("EWKB line string must be empty or contain at least two coordinates");
        }
        inspectFiniteCoordinates(cursor, byteOrder, coordinateCount, coordinateDimension);
    }

    private void inspectLinearRing(WkbCursor cursor, ByteOrder byteOrder, int coordinateDimension) {
        int coordinateCount = readCount(cursor, byteOrder);
        if (coordinateCount < 4) {
            throw new IllegalArgumentException("EWKB linear ring must contain at least four coordinates");
        }

        double[] firstCoordinate = readFiniteCoordinate(cursor, byteOrder, coordinateDimension);
        inspectFiniteCoordinates(cursor, byteOrder, coordinateCount - 2, coordinateDimension);
        double[] lastCoordinate = readFiniteCoordinate(cursor, byteOrder, coordinateDimension);
        for (int i = 0; i < 2; i++) {
            if (firstCoordinate[i] != lastCoordinate[i]) {
                throw new IllegalArgumentException("EWKB linear ring is not closed");
            }
        }
    }

    private void inspectFiniteCoordinates(WkbCursor cursor, ByteOrder byteOrder,
                                          int coordinateCount, int coordinateDimension) {
        for (int coordinate = 0; coordinate < coordinateCount; coordinate++) {
            for (int ordinate = 0; ordinate < coordinateDimension; ordinate++) {
                if (!Double.isFinite(cursor.readDouble(byteOrder))) {
                    throw new IllegalArgumentException("EWKB coordinate is not finite");
                }
            }
        }
    }

    private double[] readFiniteCoordinate(WkbCursor cursor, ByteOrder byteOrder, int coordinateDimension) {
        double[] coordinate = new double[coordinateDimension];
        for (int i = 0; i < coordinateDimension; i++) {

View on GitHub (pinned to 5ee1e990e7)

Solutions

  1. No action required in production — convertJDBCValueByType catches this and returns the raw hex value
  2. Repair the source data by appending the first coordinate as the last to close each ring
  3. Use ST_MakeValid in PostgreSQL to automatically close rings where possible

Example fix

-- before: unclosed ring (first point != last point)
SELECT ST_GeomFromEWKT('POLYGON((0 0, 1 0, 1 1, 0 1))');
-- after: closed ring (first point == last point)
SELECT ST_GeomFromEWKT('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))');
Defensive patterns

Strategy: try-catch

Validate before calling

// Already caught in convertJDBCValueByType. For data-level validation:
// SELECT gid, ST_IsValidDetail(geom) FROM my_table WHERE NOT ST_IsClosed(ST_ExteriorRing(geom));

Try / catch

try {
    inspectEwkb(ewkb);
} catch (IllegalArgumentException e) {
    log.debug("EWKB ring not closed", e);
    return value;
}

Prevention

When it happens

Trigger: Converting a PostgreSQL POLYGON geometry whose EWKB declares a ring with >=4 coordinates but where the first coordinate's X or Y differs from the last coordinate's X or Y. The comparison at line 248 checks firstCoordinate[i] != lastCoordinate[i] for i in {0,1}.

Common situations: Data where the closing point was omitted or mismatched; polygon rings serialized without the closing vertex; coordinate precision differences between systems that drop the closing point.

Related errors


AI-assisted analysis of OtterMind/Chat2DB@5ee1e990e7 (2026-08-14). Data as JSON: /api/errors/8e8c6e7190c2b208. Report an issue: GitHub.