{"record":{"id":"43dfa21230be09e2","repo":"elastic/elasticsearch","slug":"invalid-cell","errorCode":null,"errorMessage":"Invalid cell: {}","messagePattern":"Invalid cell: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"libs/h3/src/main/java/org/elasticsearch/h3/HexRing.java","lineNumber":594,"sourceCode":"    private static final CoordIJK.Direction[] NEIGHBORSETCOUNTERCLOCKWISE = new CoordIJK.Direction[] {\n        CoordIJK.Direction.CENTER_DIGIT,\n        CoordIJK.Direction.IK_AXES_DIGIT,\n        CoordIJK.Direction.JK_AXES_DIGIT,\n        CoordIJK.Direction.K_AXES_DIGIT,\n        CoordIJK.Direction.IJ_AXES_DIGIT,\n        CoordIJK.Direction.I_AXES_DIGIT,\n        CoordIJK.Direction.J_AXES_DIGIT };\n\n    /**\n     * Returns whether or not the provided H3Indexes are neighbors.\n     * @param origin The origin H3 index.\n     * @param destination The destination H3 index.\n     * @return true if the indexes are neighbors, false otherwise\n     */\n    public static boolean areNeighbours(long origin, long destination) {\n        // Make sure they're hexagon indexes\n        if (H3Index.H3_get_mode(origin) != Constants.H3_CELL_MODE) {\n            throw new IllegalArgumentException(\"Invalid cell: \" + origin);\n        }\n\n        if (H3Index.H3_get_mode(destination) != Constants.H3_CELL_MODE) {\n            throw new IllegalArgumentException(\"Invalid cell: \" + destination);\n        }\n\n        // Hexagons cannot be neighbors with themselves\n        if (origin == destination) {\n            return false;\n        }\n\n        final int resolution = H3Index.H3_get_resolution(origin);\n        // Only hexagons in the same resolution can be neighbors\n        if (resolution != H3Index.H3_get_resolution(destination)) {\n            return false;\n        }\n\n        // H3 Indexes that share the same parent are very likely to be neighbors","sourceCodeStart":576,"sourceCodeEnd":612,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/h3/src/main/java/org/elasticsearch/h3/HexRing.java#L576-L612","documentation":"Thrown by HexRing.areNeighbours (exposed via H3.areNeighborCells) when the ORIGIN index's mode field is not H3_CELL_MODE. H3 packs type information into the index; a non-cell-mode long is either an edge/ directed-edge index, a corrupt value, or a non-H3 long. The method refuses to reason about neighbors of a non-cell.","triggerScenarios":"Calling H3.areNeighborCells(a, b) where a (the origin) is not a cell-mode index: an edge index from a different H3 API, a corrupted long, or a value that was never a valid H3 cell. The destination is checked separately at [637].","commonSituations":"Intermixing cell indexes with edge indexes (H3 edge APIs return a different mode bit); reading indexes from an untrusted/external store without validation; bit-rot or endianness errors when serializing H3 longs across systems.","solutions":["Gate inputs with H3.h3IsValid(origin) && H3.h3IsValid(destination) before calling areNeighborCells.","If your pipeline includes edge indexes, keep cell and edge longs in distinct types/channels and never cross them.","Re-derive indexes from coordinates via geoToH3 rather than trusting opaque longs from external sources."],"exampleFix":"// before\nboolean near = H3.areNeighborCells(maybeCell, other); // throws if maybeCell is an edge index\n\n// after\nboolean near = H3.h3IsValid(maybeCell) && H3.h3IsValid(other)\n    && H3.areNeighborCells(maybeCell, other);","handlingStrategy":"validation","validationCode":"static boolean safeNeighbors(long a, long b) {\n    if (!org.elasticsearch.h3.H3.h3IsValid(a) || !org.elasticsearch.h3.H3.h3IsValid(b)) {\n        return false; // or throw at the trust boundary\n    }\n    return org.elasticsearch.h3.H3.areNeighborCells(a, b);\n}","typeGuard":"static boolean isCell(long h3) {\n    return org.elasticsearch.h3.H3.h3IsValid(h3);\n}","tryCatchPattern":"try {\n    return H3.areNeighborCells(a, b);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Invalid cell:\")) {\n        // e.getMessage() includes the bad origin value\n        return false;\n    }\n    throw e;\n}","preventionTips":["Validate both indexes with h3IsValid before adjacency calls.","Keep cell and edge longs in separate types/channels.","Re-derive indexes from geoToH3 rather than trusting opaque longs."],"tags":["h3","neighbor","validation","index"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}