{"record":{"id":"04d590d199485582","repo":"elastic/elasticsearch","slug":"invalid-child-position","errorCode":null,"errorMessage":"invalid child position","messagePattern":"invalid child position","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"libs/h3/src/main/java/org/elasticsearch/h3/H3.java","lineNumber":273,"sourceCode":"        return h3ToStringList(h3ToChildren(stringToH3(h3Address)));\n    }\n\n    /**\n     * Returns the child cell at the given position\n     */\n    public static long childPosToH3(long h3, int childPos) {\n        final int childrenRes = H3Index.H3_get_resolution(h3) + 1;\n        if (childrenRes > MAX_H3_RES) {\n            throw new IllegalArgumentException(\"Resolution overflow\");\n        }\n        final long childH = H3Index.H3_set_resolution(h3, childrenRes);\n        if (childPos == 0) {\n            return H3Index.H3_set_index_digit(childH, childrenRes, CoordIJK.Direction.CENTER_DIGIT.digit());\n        }\n        final boolean isPentagon = isPentagon(h3);\n        final int maxPos = isPentagon ? 5 : 6;\n        if (childPos < 0 || childPos > maxPos) {\n            throw new IllegalArgumentException(\"invalid child position\");\n        }\n        if (isPentagon) {\n            // Pentagon skip digit (position) is the number 1, therefore we add one\n            // to the current position.\n            return H3Index.H3_set_index_digit(childH, childrenRes, childPos + 1);\n        } else {\n            return H3Index.H3_set_index_digit(childH, childrenRes, childPos);\n        }\n    }\n\n    /**\n     * Returns the child address at the given position\n     */\n    public static String childPosToH3(String h3Address, int childPos) {\n        return h3ToString(childPosToH3(stringToH3(h3Address), childPos));\n    }\n\n    private static final int[] PEN_INTERSECTING_CHILDREN_DIRECTIONS = new int[] { 3, 1, 6, 4, 2 };","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/h3/src/main/java/org/elasticsearch/h3/H3.java#L255-L291","documentation":"Thrown by H3.childPosToH3 when childPos is negative or exceeds the valid range for the cell's shape: 0..6 for hexagons (center + 6 edges) and 0..5 for pentagons (center + 5 edges, since the k-axis digit is skipped). The position must index into the cell's finite child set.","triggerScenarios":"Calling childPosToH3(cell, n) with n out of the legal band for that cell. A pentagon parent restricts positions to 0..5, so passing 6 against a pentagon throws; a hexagon parent accepts up to 6.","commonSituations":"Assuming 7 children for every cell and passing position 6 against a pentagon; computing positions from a hexagon-sized loop applied to a pentagon; off-by-one indexing from a caller that uses 1-based positions.","solutions":["Bound the loop by H3.h3ToChildrenSize(cell) (returns 7 for hexagons, 6 for pentagons) rather than a hardcoded 7.","If accepting arbitrary user positions, validate 0 <= pos < h3ToChildrenSize(cell) before calling.","Remember pentagons have one fewer child position (the deleted k-axis); never assume uniform 7."],"exampleFix":"// before\nfor (int i = 0; i <= 6; i++) { // wrong for pentagons\n    long child = H3.childPosToH3(cell, i);\n}\n\n// after\nfor (int i = 0; i < H3.h3ToChildrenSize(cell); i++) {\n    long child = H3.childPosToH3(cell, i);\n}","handlingStrategy":"validation","validationCode":"static long safeChildPos(long h3, int pos) {\n    int max = org.elasticsearch.h3.H3.h3ToChildrenSize(h3); // 7 hex / 6 pentagon\n    if (pos < 0 || pos >= max) {\n        throw new IllegalArgumentException(\"pos \" + pos + \" out of [0,\" + max + \")\");\n    }\n    return org.elasticsearch.h3.H3.childPosToH3(h3, pos);\n}","typeGuard":"static boolean validChildPos(long h3, int pos) {\n    return pos >= 0 && pos < org.elasticsearch.h3.H3.h3ToChildrenSize(h3);\n}","tryCatchPattern":"try {\n    return H3.childPosToH3(h3, pos);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().equals(\"invalid child position\")) {\n        throw new IndexOutOfBoundsException(\"childPos \" + pos + \" invalid for \" + h3);\n    }\n    throw e;\n}","preventionTips":["Bound iteration by h3ToChildrenSize, not a hardcoded 7.","Remember pentagons have 6 child positions, hexagons 7.","Validate external position inputs against the cell-specific max."],"tags":["h3","child","pentagon","validation"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}