{"record":{"id":"8228a28a3fce9884","repo":"elastic/elasticsearch","slug":"invalid-ring-position","errorCode":null,"errorMessage":"invalid ring position","messagePattern":"invalid ring position","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"libs/h3/src/main/java/org/elasticsearch/h3/H3.java","lineNumber":404,"sourceCode":"     * @param h3Address Origin index\n     * @return the number of neighbor indexes from the origin\n     */\n    public static int hexRingSize(String h3Address) {\n        return hexRingSize(stringToH3(h3Address));\n    }\n\n    /**\n     * Returns the neighbor index at the given position.\n     *\n     * @param h3 Origin index\n     * @param ringPos position of the neighbour index\n     * @return the actual neighbour at the given position\n     */\n    public static long hexRingPosToH3(long h3, int ringPos) {\n        // for pentagons, we skip direction at position 2\n        final int pos = H3Index.H3_is_pentagon(h3) && ringPos >= 2 ? ringPos + 1 : ringPos;\n        if (pos < 0 || pos > 5) {\n            throw new IllegalArgumentException(\"invalid ring position\");\n        }\n        return HexRing.h3NeighborInDirection(h3, HexRing.DIRECTIONS[pos].digit());\n    }\n\n    /**\n     * Returns the neighbor index at the given position.\n     *\n     * @param h3Address Origin index\n     * @param ringPos position of the neighbour index\n     * @return the actual neighbour at the given position\n     */\n    public static String hexRingPosToH3(String h3Address, int ringPos) {\n        return h3ToString(hexRingPosToH3(stringToH3(h3Address), ringPos));\n    }\n\n    /**\n     * returns whether or not the provided hexagons border\n     *","sourceCodeStart":386,"sourceCodeEnd":422,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/h3/src/main/java/org/elasticsearch/h3/H3.java#L386-L422","documentation":"Thrown by H3.hexRingPosToH3 when the effective position is not in [0,5]. For pentagons, positions >= 2 are shifted by +1 (to skip the missing k-axis direction), so a raw ringPos of 6 on a pentagon maps to effective 7 and is caught; negative positions always throw. Hexagons accept 0..5 directly.","triggerScenarios":"Calling hexRingPosToH3(cell, n) with n negative, or n > 5 on a hexagon, or n > 5 on a pentagon (since pentagons remap n>=2 and thus n=6 -> effective 7 throws). The public H3.hexRing iterates 0..hexRingSize-1 (5 or 6), so direct callers passing unbounded n are the risk.","commonSituations":"Caller iterating 0..6 unconditionally instead of using hexRingSize; assuming 6 neighbors for pentagons (they have 5); passing a ring position sourced from a different H3 version's enumeration.","solutions":["Bound the loop by H3.hexRingSize(cell) (6 hex / 5 pentagon), never a hardcoded 6.","Validate 0 <= ringPos < hexRingSize(cell) before calling.","Remember pentagons have 5 ring positions; let hexRingSize drive the bound."],"exampleFix":"// before\nfor (int i = 0; i <= 6; i++) { // throws on pentagons / on i=6\n    long nb = H3.hexRingPosToH3(cell, i);\n}\n\n// after\nfor (int i = 0; i < H3.hexRingSize(cell); i++) {\n    long nb = H3.hexRingPosToH3(cell, i);\n}","handlingStrategy":"validation","validationCode":"static long safeRingPos(long h3, int pos) {\n    int max = org.elasticsearch.h3.H3.hexRingSize(h3); // 6 hex / 5 pentagon\n    if (pos < 0 || pos >= max) {\n        throw new IllegalArgumentException(\"ringPos \" + pos + \" out of [0,\" + max + \")\");\n    }\n    return org.elasticsearch.h3.H3.hexRingPosToH3(h3, pos);\n}","typeGuard":"static boolean validRingPos(long h3, int pos) {\n    return pos >= 0 && pos < org.elasticsearch.h3.H3.hexRingSize(h3);\n}","tryCatchPattern":"try {\n    return H3.hexRingPosToH3(h3, pos);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().equals(\"invalid ring position\")) {\n        throw new IndexOutOfBoundsException(\"ringPos \" + pos + \" invalid for \" + h3);\n    }\n    throw e;\n}","preventionTips":["Always bound loops by hexRingSize (5 for pentagons).","Never assume 6 neighbors; pentagons have 5.","Prefer H3.hexRing(h3) over manual position iteration."],"tags":["h3","ring","pentagon","validation"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}