oracle/graal · error · PermanentBailoutException
Compilation exceeded %.3f seconds%s. %n Phase timings:%n %s
Error message
Compilation exceeded %.3f seconds%s. %n Phase timings:%n %s <===== TIMEOUT HERE
What it means
CompilationAlarm throws this PermanentBailoutException when a Graal compilation runs longer than its configured time budget (the alarm's period). The message includes total elapsed seconds, optional GC time, and a phase-timing tree marking the phase that was active when the alarm fired ('<===== TIMEOUT HERE'). Permanent bailout means the compilation is abandoned and (in a JVM setting) the method falls back to a lower tier rather than crashing.
Source
Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/util/CompilationAlarm.java:207
/*
* We clone the phase tree here for the sake of the error message. We want to fix up the
* root timings and also annotate in which phase(s) the timeout happens. We do not do
* this on the original tree because that one can still be in IGV dumps.
*/
PhaseTreeNode cloneTree = cloneTree(root, null);
StringBuilder sb = new StringBuilder();
// also update the root time to be consistent for the error message
cloneTree.durationNS = elapsed();
printTree("", sb, cloneTree, true, skipZeros);
// Include information about time spent in the GC if it's available.
String gcMessage = "";
if (gcTiming != null) {
gcMessage = String.format(" (GC time is %s ms of %s ms elapsed)", gcTiming.getGCTimeMillis(), gcTiming.getElapsedTimeMillis());
}
throw new PermanentBailoutException("Compilation exceeded %.3f seconds%s. %n Phase timings:%n %s <===== TIMEOUT HERE", period, gcMessage, sb.toString().trim());
}
}
@Override
public void close() {
currentAlarm.set(previous);
resetProgressDetection();
}
/**
* Expiration period (in seconds) of this alarm.
*/
private double period;
/**
* The time at which this alarm expires in nanoseconds.
*/
private long expirationNS;View on GitHub (pinned to a66e9ccd1d)
Solutions
- Read the phase-timing tree in the message: it names the phase that hit the limit — that is where the investigation (or bug report) should focus.
- Raise or disable the compilation time limit option that armed the alarm (check the embedding VM's / Graal's option for the alarm period) if the machine is legitimately slow.
- Exclude the offending method from Graal compilation (-XX:CompileCommand=exclude) or shrink it / limit inlining (-Dgraal.MaximumDesiredSize, -Dgraal.LimitInlinedCalls) so it compiles within budget.
- If the timing tree shows one phase dominating on a normal method, file a Graal performance issue with the graph dump.
Defensive patterns
Strategy: try-catch
Try / catch
// in an embedding host: permanent bailouts are expected, catch and fall back
try {
result = graalCompile(graph);
} catch (PermanentBailoutException e) {
if (e.getMessage().contains("Compilation exceeded")) {
result = baselineCompile(graph); // or retry with inlining disabled
} else {
throw e;
}
} Prevention
- Always implement a fallback tier when embedding Graal — PermanentBailoutException is by design recoverable.
- Size the alarm period to the slowest expected machine in your fleet, not the fastest.
- Watch the phase-timing tree in the message over time to spot creeping phase regressions.
When it happens
Trigger: A compilation exceeding the limit configured for the alarm (e.g. via Graal's compilation time limit options such as -Dgraal.CompilationTimeLimit-style settings, or the alarm set by the embedding VM with a specific period). Slow phases like huge inlining, scheduling, or register allocation on very large graphs trip it; the printed phase tree identifies which phase consumed the budget.
Common situations: Compiling giant generated methods (template engines, serialization codegen, genetic/DSL output), pathological inlining blowups, or simply overloaded CI machines where wall-clock budgets are exceeded. Also seen after upgrades that regress a phase's complexity, or on very slow/emulated hardware (QEMU) where time-based limits calibrated for native speed fire spuriously.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Observed identical stack traces for %d ms, indicating a stuc
- 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/271980c6b40574a3.
Report an issue: GitHub.