{"record":{"id":"716b77de5c275312","repo":"oracle/graal","slug":"too-deep-inlining-probably-caused-by-recursive-in","errorCode":null,"errorMessage":"Too deep inlining, probably caused by recursive inlining.","messagePattern":"Too deep inlining, probably caused by recursive inlining\\.","errorType":"exception","errorClass":"PermanentBailoutException","httpStatus":null,"severity":"error","filePath":"compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/PEGraphDecoder.java","lineNumber":1673,"sourceCode":"        List<Map.Entry<ResolvedJavaMethod, Integer>> methods = new ArrayList<>(methodCounts.entrySet());\n        methods.sort((e1, e2) -> -Integer.compare(e1.getValue(), e2.getValue()));\n\n        StringBuilder msg = new StringBuilder(\"Too deep inlining, probably caused by recursive inlining.\").append(System.lineSeparator()).append(\"== Inlined methods ordered by inlining frequency:\");\n        for (Map.Entry<ResolvedJavaMethod, Integer> entry : methods) {\n            msg.append(System.lineSeparator()).append(entry.getKey().format(\"%H.%n(%p) [\")).append(entry.getValue()).append(\"]\");\n        }\n        msg.append(System.lineSeparator()).append(\"== Complete stack trace of inlined methods:\");\n        int lastBci = 0;\n        for (PEMethodScope cur = methodScope; cur != null; cur = cur.caller) {\n            msg.append(System.lineSeparator()).append(cur.method.asStackTraceElement(lastBci));\n            if (cur.invokeData != null) {\n                lastBci = cur.invokeData.invoke.bci();\n            } else {\n                lastBci = 0;\n            }\n        }\n\n        throw new PermanentBailoutException(msg.toString());\n    }\n\n    protected FixedNode nodeAfterInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, BeginNode prevBegin) {\n        assert prevBegin == null || prevBegin.isAlive();\n        if (invokeData.invoke instanceof InvokeWithExceptionNode) {\n            if (prevBegin != null && getNodeClass(methodScope, loopScope, invokeData.nextOrderId) == prevBegin.getNodeClass()) {\n                // Reuse the previous Node but mark it in nodesToProcess so that the decoding loop\n                // continues decoding.\n                loopScope.nodesToProcess.set(invokeData.nextOrderId);\n                registerNode(loopScope, invokeData.nextOrderId, prevBegin, false, false);\n                return prevBegin;\n            }\n        }\n        return makeStubNode(methodScope, loopScope, invokeData.nextOrderId);\n    }\n\n    private static void deleteInvoke(Invoke invoke) {\n        /*","sourceCodeStart":1655,"sourceCodeEnd":1691,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/PEGraphDecoder.java#L1655-L1691","documentation":"While decoding snippet/intrinsic graphs, PEGraphDecoder tracks inlining depth. When inlining during decoding exceeds the allowed depth, it builds a diagnostic message listing the full chain of inlined methods (the code around PEGraphDecoder.java:1673) and throws PermanentBailoutException with 'Too deep inlining, probably caused by recursive inlining.' The named methods show the recursion cycle.","triggerScenarios":"A snippet or intrinsic whose partial-evaluation graph recursively inlines itself (directly or through a cycle of snippets), each level increasing decode depth until the limit is hit.","commonSituations":"Writing a snippet that calls a method that is itself lowered to the same snippet; snippets with unguarded recursive helper calls; changing a method from regular to @Snippet so a pre-existing recursion now becomes snippet recursion.","solutions":["Read the '== Complete stack trace of inlined methods ==' section in the message to find the cycle, then break the recursion (base-case check, non-snippet escape, or different snippet for the recursive step)","Mark the recursive helper as not-inlinable or move it out of the snippet","If this occurs without custom snippets, report a GraalVM bug with the stack section"],"exampleFix":"// before\n@Snippet static int len(Object[] a, int i) { return i >= a.length ? 0 : 1 + len(a, i + 1); }\n\n// after\nstatic int len(Object[] a, int i) { ... } // non-snippet recursive helper\n@Snippet static int lenSnippet(Object[] a) { return len(a, 0); }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    graph = replacements.getSnippet(...);\n} catch (PermanentBailoutException e) {\n    // message contains the inlined-method cycle; fix the recursive snippet, then recompile\n    log.error(\"snippet recursion: {}\", e.getMessage());\n}","preventionTips":["Never make a snippet transitively lower to itself; hoist recursion into non-snippet code","Read the 'Complete stack trace of inlined methods' section to spot the cycle instantly"],"tags":["graal","partial-evaluation","inlining","recursion","snippet"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}