{"record":{"id":"b418292cd0c31941","repo":"oracle/graal","slug":"endless-collision-link-cycle-most-likely-due-to-u","errorCode":null,"errorMessage":"endless collision link cycle, most likely due to unsynchronized concurrent access","messagePattern":"endless collision link cycle, most likely due to unsynchronized concurrent access","errorType":"exception","errorClass":"InternalError","httpStatus":null,"severity":"critical","filePath":"sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMapImpl.java","lineNumber":624,"sourceCode":"            Object entryKey = getKey(i);\n            if (entryKey != null) {\n                putHashEntry(entryKey, i, false);\n            }\n        }\n    }\n\n    private void putHashEntry(Object key, int entryIndex, boolean rehashOnCollision) {\n        int hashIndex = getHashIndex(key);\n        int oldIndex = getHashArray(hashIndex) - 1;\n        if (oldIndex != -1 && rehashOnCollision) {\n            this.createHash();\n            return;\n        }\n        setHashArray(hashIndex, entryIndex + 1);\n        Object value = getRawValue(entryIndex);\n        if (oldIndex != -1) {\n            if (entryIndex == oldIndex) {\n                throw new InternalError(\"endless collision link cycle, most likely due to unsynchronized concurrent access\");\n            }\n            if (value instanceof CollisionLink collisionLink) {\n                setRawValue(entryIndex, new CollisionLink(collisionLink.value, oldIndex));\n            } else {\n                setRawValue(entryIndex, new CollisionLink(value, oldIndex));\n            }\n        } else {\n            if (value instanceof CollisionLink collisionLink) {\n                setRawValue(entryIndex, collisionLink.value);\n            }\n        }\n    }\n\n    @Override\n    public int size() {\n        return totalEntries - deletedEntries;\n    }\n","sourceCodeStart":606,"sourceCodeEnd":642,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EconomicMapImpl.java#L606-L642","documentation":"EconomicMapImpl is not thread-safe. putHashEntry() builds collision links and detects the degenerate case where an entry would link to itself (entryIndex == oldIndex), which cannot happen in correct single-threaded operation and indicates two threads mutated the map concurrently and corrupted its hash links; it then throws InternalError.","triggerScenarios":"Two or more threads calling put/putIfAbsent/remove (or rehash-triggering operations) on the same EconomicMapImpl without external synchronization; by the time this fires, the map structure is already corrupt.","commonSituations":"Sharing a map created with EconomicMap.create() across compiler/parsing threads; refactoring previously single-threaded code to parallel streams; caches populated lazily from multiple workers.","solutions":["Use the concurrent variant: EconomicMapWrap around ConcurrentHashMap (new EconomicMapWrap<>(new ConcurrentHashMap<>())) for shared maps.","Alternatively guard every access with external synchronization (same lock for reads and writes) - but the concurrent wrapper is simpler and faster.","After fixing, audit for other unsynchronized EconomicMaps shared by the same threads; corruption may have been silently degrading them too."],"exampleFix":"// before\nEconomicMap<String, Object> shared = EconomicMap.create();\n// ... written from multiple threads -> InternalError\n\n// after\nEconomicMap<String, Object> shared = new EconomicMapWrap<>(new ConcurrentHashMap<>());","handlingStrategy":"fallback","validationCode":"// No pre-call check can detect races; enforce ownership instead:\nassert Thread.holdsLock(guard) || singleThreadedContext : \"EconomicMapImpl must not be shared unsynchronized\"","typeGuard":null,"tryCatchPattern":"// Do NOT catch and continue: the map is already corrupt.\n// Catch only to fail fast with context, then rebuild state:\ntry {\n    map.put(k, v);\n} catch (InternalError e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"collision link cycle\")) {\n        throw new IllegalStateException(\"EconomicMap corrupted by concurrent access\", e);\n    }\n    throw e;\n}","preventionTips":["Never share EconomicMapImpl across threads; use EconomicMapWrap(new ConcurrentHashMap<>()) for shared maps.","If external synchronization is unavoidable, guard reads and writes with the same lock.","Treat this InternalError as a defect report: fix the sharing pattern, do not retry on the corrupted map."],"tags":["graalvm","collections","economic-map","concurrency","java"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}