{"record":{"id":"026b1f29cfebb1c6","repo":"oracle/graal","slug":"index-should-be-an-int","errorCode":null,"errorMessage":"Index should be an int","messagePattern":"Index should be an int","errorType":"exception","errorClass":"ArrayIndexOutOfBoundsException","httpStatus":null,"severity":"warning","filePath":"espresso-compiler-stub/src/com.oracle.truffle.espresso.vmaccess/src/com/oracle/truffle/espresso/vmaccess/EspressoExternalHostProxies.java","lineNumber":363,"sourceCode":"\n    private Value computeGuestMethodMap(Class<?> hostClass, EspressoExternalResolvedInstanceType guestType) {\n        Map<String, ProxyExecutable> map = computeMethodMap(hostClass, guestType);\n        ProxyObject invocables = new ProxyObject() {\n            @Override\n            public Object getMember(String key) {\n                return map.get(key);\n            }\n\n            @Override\n            public Object getMemberKeys() {\n                Object[] keys = map.keySet().toArray();\n                return new ProxyArray() {\n                    @Override\n                    public Object get(long index) {\n                        try {\n                            return keys[Math.toIntExact(index)];\n                        } catch (ArithmeticException e) {\n                            throw new ArrayIndexOutOfBoundsException(\"Index should be an int\");\n                        }\n                    }\n\n                    @Override\n                    public void set(long index, Value value) {\n                        throw new UnsupportedOperationException(\"set() not supported.\");\n                    }\n\n                    @Override\n                    public long getSize() {\n                        return keys.length;\n                    }\n                };\n            }\n\n            @Override\n            public boolean hasMember(String key) {\n                return map.containsKey(key);","sourceCodeStart":345,"sourceCodeEnd":381,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/espresso-compiler-stub/src/com.oracle.truffle.espresso.vmaccess/src/com/oracle/truffle/espresso/vmaccess/EspressoExternalHostProxies.java#L345-L381","documentation":"ArrayIndexOutOfBoundsException ('Index should be an int') thrown by the ProxyArray view of a host object's member keys in EspressoExternalHostProxies.getMemberKeys: the polyglot long index passed to get(long) overflows int range, so Math.toIntExact(index) throws ArithmeticException, which is converted to this AIOOBE. Polyglot array indices are longs, but the backing Java key array is indexed by int, so any index outside [0, Integer.MAX_VALUE] (including negatives or values > 2^31-1) cannot be served.","triggerScenarios":"Guest language code iterating the array-shaped mirror of a host object's member keys with an index larger than Integer.MAX_VALUE or negative; a guest runtime probing ProxyArray.getSize/get bounds incorrectly and calling get() with a huge sentinel index.","commonSituations":"JS or other guest engines performing sparse-array probing (reading index 2^32 or beyond to detect array holes); guest code passing an unvalidated user-supplied index straight into the polyglot array access; interop with languages whose arrays are long-indexed (e.g. some native engines).","solutions":["Guest-side: clamp/validate indices to 0 <= index < getSize() before accessing member keys.","Host-side: treat this exception as 'index out of the representable range' and return undefined/holes for huge indices instead of failing the iteration.","If a guest engine probes with sentinel indices, ensure the engine's interop layer is current — newer Truffle versions probe less aggressively.","Report a bug only if the index is within [0, size) and still fails; that would indicate a genuine provider defect."],"exampleFix":"// before (guest interop caller)\nfor (let i = 0; i < 2 ** 33; i++) readKeyAt(i); // long probe hits get(Long.MAX)\n\n// after\nconst n = memberKeys.getSize(); // long\nfor (let i = 0; i < n && i < 2147483647; i++) readKeyAt(i);","handlingStrategy":"validation","validationCode":"// guest/interop side: bounds-check against size before read\nlong n = memberKeys.getSize();\nif (index < 0 || index >= n || index > Integer.MAX_VALUE) {\n    return undefinedOrError(index); // out of representable range\n}\nreturn memberKeys.get(index);","typeGuard":null,"tryCatchPattern":"try { return keysProxy.get(idx); } catch (ArrayIndexOutOfBoundsException e) { /* index not representable as int: treat as hole/undefined */ }","preventionTips":["Clamp guest array access on interop mirrors to 0 <= index < size.","Do not pass sentinel/probe indices (e.g. Long.MAX_VALUE) into polyglot array reads.","Keep Truffle/guest-engine versions current to avoid aggressive sparse-array probing."],"tags":["polyglot","truffle","proxy-array","index-overflow","interop"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}