oracle/graal · error · PermanentBailoutException
At %s, bci %s: opcode %s (%s) has a stack effect of %s, the
Error message
At %s, bci %s: opcode %s (%s) has a stack effect of %s, the stack size is %s + %s, this will underflow the bytecode stack.
What it means
FrameStateBuilder.check JDK26-style stack-usage verifier: before an opcode is processed, it computes stackSize + pushedSlotCount + stackEffectOf(opcode) and permanently bails out if the result is negative — the instruction would pop more values than exist on the operand stack (stack underflow). Well-formed, verified bytecode never triggers this; hitting it means the bytecode is malformed or the frame state tracking diverged from reality.
Source
Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/FrameStateBuilder.java:440
return;
}
if (rethrowException) {
/*
* We seem to be inside explicit exception handling code, with the operation's inputs
* already popped off the stack and an exception pushed instead. We can't recover the
* original stack size for verification.
*/
return;
}
int pushedSlotCount = 0;
if (pushedSlotKinds != null) {
for (JavaKind pushedKind : pushedSlotKinds) {
pushedSlotCount += pushedKind.getSlotCount();
}
}
if (stackSize + pushedSlotCount + Bytecodes.stackEffectOf(opcode) < 0) {
throw new PermanentBailoutException("At %s, bci %s: opcode %s (%s) has a stack effect of %s, the stack size is %s + %s, this will underflow the bytecode stack.",
code, bci, opcode & 0xff, Bytecodes.nameOf(opcode), Bytecodes.stackEffectOf(opcode), stackSize, pushedSlotCount);
}
}
public NodeSourcePosition createBytecodePosition(int bci) {
BytecodeParser parent = parser.getParent();
NodeSourcePosition position = create(bci, parent);
return position;
}
private NodeSourcePosition create(int bci, BytecodeParser parent) {
if (outerSourcePosition == null && parent != null) {
outerSourcePosition = parent.getFrameStateBuilder().createBytecodePosition(parent.bci());
}
if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
return FrameState.toSourcePosition(outerFrameState);
}
if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {View on GitHub (pinned to a66e9ccd1d)
Solutions
- Run the class through a strict verifier (`java -Xverify:all -Xshare:off`) or a bytecode checker to confirm and locate the malformed method.
- Fix or regenerate the bytecode so each branch target has a consistent stack shape.
- If verification passes, capture the bci/opcode from the message and report a Graal compiler issue with the reproducing class.
Defensive patterns
Strategy: validation
Validate before calling
// verify stack consistency at every branch target before shipping the class file // tools: `java -Xverify:all`, ASM CheckClassAdapter, or jacoco/spotbugs bytecode checks
Prevention
- Run strict bytecode verification on all generated classes in CI.
- When writing ASM transformers, recompute stack-map frames and test on both int and long paths (TWO_SLOT handling).
When it happens
Trigger: FrameStateBuilder stack check firing for an opcode at a bci where the tracked stack size plus the values pushed by the current operation is smaller than the opcode's pop count — typical of hand-written/modified bytecode that fails verification, or of long/complex values (TWO_SLOT_MARKER handling) confusing the slot accounting.
Common situations: Malformed class files from broken generators or aggressive obfuscators; instrumentation agents inserting pops/branches that leave the stack inconsistent; rare Graal frame-state bugs after unusual store/load sequences — the message includes code, bci, opcode, stack effect and sizes to pinpoint it.
Related errors
- OSR with stack entries not supported: %s
- unbalanced monitors - locked objects do not match
- unbalanced monitors - monitors do not match
- OSR compilation without OSR entry loop.
- OSR with locks disabled.
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/f88cc8f1b96769ff.
Report an issue: GitHub.