oracle/graal · error · PermanentBailoutException
Observed identical stack traces for %d ms, indicating a stuc
Error message
Observed identical stack traces for %d ms, indicating a stuck compilation, counter = %s, stack is:%n%s
What it means
CompilationAlarm's progress detection periodically samples the compiling thread's stack trace; if the same stack persists longer than the stuck threshold (a wall-clock duration measured from the last unique trace), it concludes the compilation is not making progress and throws this PermanentBailoutException with the elapsed ms, the alarm counter, and the frozen stack. Like error 28 it aborts just the compilation, not the VM.
Source
Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/util/CompilationAlarm.java:668
}
assert Arrays.equals(lastStackTrace, currentStackTrace) : "Must only enter this branch if no progress was made";
/*
* We have a similar stack trace - fail once the period is longer than the no progress
* period.
*/
final long lastUniqueStackTraceTime = lastUniqueStackTraceForThreadNS.get();
final long nowNS = System.nanoTime();
final long elapsedNS = nowNS - lastUniqueStackTraceTime;
boolean stuck = elapsedNS > stuckThreshold;
if (LOG_PROGRESS_DETECTION) {
TTY.printf("CompilationAlarm: Progress detection %s; no progress for %d ms; stuck? %s; stuck threshold %d ms%n",
counter, TimeUnit.NANOSECONDS.toMillis(elapsedNS), stuck, stuckThreshold);
}
if (stuck) {
throw new PermanentBailoutException("Observed identical stack traces for %d ms, indicating a stuck compilation, counter = %s, stack is:%n%s",
TimeUnit.NANOSECONDS.toMillis(elapsedNS), counter, Util.toString(lastStackTrace));
}
}
public static void resetProgressDetection() {
lastStackTraceForThread.set(null);
lastUniqueStackTraceForThreadNS.set(null);
lastMarkerForThread.set(null);
noProgressStartPeriodNS.set(null);
}
private static final ThreadLocal<StackTraceElement[]> lastStackTraceForThread = new ThreadLocal<>();
private static final ThreadLocal<Long> lastUniqueStackTraceForThreadNS = new ThreadLocal<>();
/**
* Note that all these thread locals are not necessarily reset for a while even if worker
* threads have moved on to do actual work (but just not compiling graphs). Especially in the
* native image generator, not all {@link #assertProgress} calls can be in a closeable scope
* that invokes {@link #resetProgressDetection}. It is therefore critical that they do not keepView on GitHub (pinned to a66e9ccd1d)
Solutions
- Use the stack trace embedded in the message to identify the looping phase/line, and file a Graal issue with it — a truly stuck compilation is a compiler bug.
- Exclude the affected method from Graal compilation so the baseline compiler handles it.
- If the compilation is slow but progressing (loaded CI box), raise or disable the progress-detection/stuck threshold option before disabling the feature wholesale.
- Reduce input size (smaller method, less inlining) so the phase completes between samples.
Defensive patterns
Strategy: try-catch
Try / catch
try {
result = graalCompile(graph);
} catch (PermanentBailoutException e) {
if (e.getMessage().contains("stuck compilation")) {
bugTracker.attach(e.getMessage()); // message contains the frozen stack
result = baselineCompile(graph);
} else {
throw e;
}
} Prevention
- Harvest the embedded stack trace — it is exactly the evidence a compiler bug report needs.
- Keep a corpus of the largest methods your product compiles and run it through new Graal builds to catch non-linear phase blowups early.
- On heavily loaded machines, scale the stuck threshold with measured compile throughput.
When it happens
Trigger: A single compilation thread executing one phase for longer than the stuck threshold without the stack changing — typically a super-linear algorithm inside one optimization phase (e.g. a quadratic loop in scheduling, inlining, or graph cleanup) on a very large graph. Repeated samples return identical StackTraceElements, crossing the threshold.
Common situations: Large generated methods or adversarial benchmarks that trigger complexity blowups in a Graal phase; regressions after a Graal upgrade; heavily loaded machines where the stuck threshold is too aggressive for slow-but-progressing compilations. The frozen stack in the message names the exact method and line that was spinning.
Related errors
- Compilation exceeded %.3f seconds%s. %n Phase timings:%n %s
- OSR compilation without OSR entry loop.
- OSR with locks disabled.
- OSR with stack entries not supported: %s
- Number of elements in a node list too high: %d
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/5a2998ce0422dc4e.
Report an issue: GitHub.