{"record":{"id":"f6f2ed1ec141e149","repo":"oracle/graal","slug":"number-of-elements-in-a-node-list-too-high-d","errorCode":null,"errorMessage":"Number of elements in a node list too high: %d","messagePattern":"Number of elements in a node list too high: (.+?)","errorType":"exception","errorClass":"PermanentBailoutException","httpStatus":null,"severity":"error","filePath":"compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/NodeList.java","lineNumber":124,"sourceCode":"            this.size = 0;\n            this.nodes = Node.EMPTY_ARRAY;\n            this.initialSize = 0;\n        } else {\n            int newSize = elements.size();\n            checkMaxSize(newSize);\n            this.size = newSize;\n            this.initialSize = newSize;\n            this.nodes = new Node[elements.size()];\n            for (int i = 0; i < elements.size(); i++) {\n                this.nodes[i] = elements.get(i);\n                assert this.nodes[i] == null || !this.nodes[i].isDeleted();\n            }\n        }\n    }\n\n    private static void checkMaxSize(int value) {\n        if (value > MAX_ENTRIES) {\n            throw new PermanentBailoutException(\"Number of elements in a node list too high: %d\", value);\n        }\n    }\n\n    /**\n     * Removes {@code null} values from the list.\n     */\n    public void trim() {\n        self.incModCount();\n        int newSize = 0;\n        for (int i = 0; i < size; ++i) {\n            if (nodes[i] != null) {\n                nodes[newSize] = nodes[i];\n                newSize++;\n            }\n        }\n        GraalError.guarantee(newSize <= size, \"size cannot increase when removing nulls\");\n        size = newSize;\n    }","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/NodeList.java#L106-L142","documentation":"NodeList is the backing store for a node's plural inputs/outputs, and its size must fit a char (MAX_ENTRIES, 65535) because the graph-dumping protocol serializes list lengths as a 16-bit short. checkMaxSize throws PermanentBailoutException when a list would exceed that hard limit. 'Permanent' tells the compilation framework not to retry: this graph can never be compiled by this backend.","triggerScenarios":"A node accumulating more than 65535 entries in a single input list: a merge/loop with tens of thousands of predecessors, a call node with a gigantic argument list, or an exploded FrameState/usage list from machine-generated Java code. Typically seen when compiling generated code with enormous methods.","commonSituations":"Compiling code-generator output or templating engines that emit methods with many thousands of statements merged at one point. Bytecode from DSL compilers producing huge switch/merge structures. Not a config error: it is a structural property of the input method; the JVM falls back to the baseline compiler for that method.","solutions":["Restructure the generated method: split the giant merge/call into several smaller merges or methods so no single node list exceeds 65535 entries.","If you control the source, reduce the number of predecessors (e.g. chunk large switch tables or chained merges into groups).","Accept the bailout: verify the method still runs on the baseline tier (PermanentBailoutException is expected to degrade gracefully).","Check for pathological graph shape first (a bug in a custom phase accidentally adding predecessors), which is fixable unlike genuinely huge input."],"exampleFix":"// generated code shape that triggers it\n// before: one merge with 100k predecessors\nmerge(allStatements());\n\n// after: chunked merges keep each list small\nmerge(chunk(allStatements(), 50_000).map(this::merge).collect(toList()));","handlingStrategy":"try-catch","validationCode":"static final int MAX_LIST = 0xFFFF; // mirrors NodeList.MAX_ENTRIES\nif (node.inputs().count() > MAX_LIST || predecessorCount > MAX_LIST) {\n    splitOrRestructure(node); // fix graph shape before it can hit the limit\n}","typeGuard":null,"tryCatchPattern":"try {\n    compileMethod(target);\n} catch (PermanentBailoutException e) {\n    // method can never JIT-compile under this backend: accept baseline tier or shrink the input method\n    log.info(\"Method too large for JIT, falling back to baseline: {}\", e.getMessage());\n}","preventionTips":["Cap the fan-in of generated merges/calls in your code generator well below 65535.","Treat this bailout as permanent for the method: do not retry the same bytecode unchanged.","Add a generator-level lint that rejects methods whose single construct can exceed the list limit."],"tags":["java","graal","graal-compiler","bailout","limits","code-generation"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}