{"record":{"id":"1b759696e8231c23","repo":"oracle/graal","slug":"this-node-is-not-alive","errorCode":null,"errorMessage":"this node is not alive: ","messagePattern":"this node is not alive: ","errorType":"exception","errorClass":"GraalGraphError","httpStatus":null,"severity":"error","filePath":"compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/NodeMap.java","lineNumber":105,"sourceCode":"        throw new UnsupportedOperationException(\"isEmpty() is not supported for performance reasons\");\n    }\n\n    @Override\n    public boolean containsKey(Node node) {\n        if (node.graph() == graph()) {\n            return get(node) != null;\n        }\n        return false;\n    }\n\n    public Graph graph() {\n        return graph;\n    }\n\n    public void set(Node node, T value) {\n        assert check(node);\n        if (!node.isAlive()) {\n            throw new GraalGraphError(\"this node is not alive: \" + node);\n        }\n        values[getNodeId(node)] = value;\n    }\n\n    public void setAndGrow(Node node, T value) {\n        checkAndGrow(node);\n        set(node, value);\n    }\n\n    /**\n     * @param i\n     * @return Return the key for the entry at index {@code i}\n     */\n    protected Node getKey(int i) {\n        return graph.getNode(i);\n    }\n\n    @Override","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/NodeMap.java#L87-L123","documentation":"NodeMap stores values in an array indexed by the node's id, which is only valid for nodes currently alive in the map's own graph. set(Node, T) therefore throws GraalGraphError when !node.isAlive(), because writing for a dead node would corrupt the id-indexed store or silently alias a recycled id. An assert additionally requires the node to belong to the same graph (node.graph() == graph).","triggerScenarios":"Calling map.set(node, value) after the node was deleted/replaced by an earlier transform in the same loop or phase. Setting values for nodes belonging to a different graph (e.g. a copied graph) — caught by the assert in debug runs. Iterating a stale node list and writing results into the map.","commonSituations":"Phases that replace nodes and then annotate them in one pass. Splitting work across phases without rebuilding the NodeMap. Using one graph's map while visiting nodes of a cloned graph (graph copies get fresh ids). Assertion-enabled dev builds also catch cross-graph misuse earlier than production runs.","solutions":["Guard every set with node.isAlive() && node.graph() == map.graph().","Compute values before mutating and write them into a fresh NodeMap created after the mutation completes.","When working on a copy of the graph, allocate a new NodeMap bound to that copy rather than reusing the original's map."],"exampleFix":"// before\nfor (Node n : nodes) {\n    transform(n); // may replace/delete n\n    map.set(n, result); // GraalGraphError: not alive\n}\n\n// after\nfor (Node n : nodes) {\n    transform(n);\n    if (n.isAlive() && n.graph() == map.graph()) {\n        map.set(n, result);\n    }\n}","handlingStrategy":"validation","validationCode":"if (node.isAlive() && node.graph() == map.graph()) {\n    map.set(node, value);\n}","typeGuard":"static boolean canStore(NodeMap<?> map, Node node) {\n    return node != null && node.isAlive() && node.graph() == map.graph();\n}","tryCatchPattern":null,"preventionTips":["Check isAlive() before every set() in loops that also replace or delete nodes.","Allocate per-graph maps; never reuse one graph's NodeMap against a copy.","Run with assertions enabled so the same-graph assert surfaces misuse early."],"tags":["java","graal","graal-compiler","nodemap","node-lifecycle","graph"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}