oracle/graal · error · GraalError
Graph was permanetly frozen.
Error message
Graph was permanetly frozen.
What it means
A Graal compiler Graph has a freeze lifecycle: Unfrozen -> TemporaryFreeze -> DeepFreeze. freeze() applies DeepFreeze, a permanent state meaning the graph will never be mutated again (e.g. it was installed in a graph cache or handed to an immutable consumer). temporaryFreeze() is a short-lived guard used during iteration/verification, and it refuses to run on a DeepFreeze graph. Hitting this error means code tried to re-enter a temporary-freeze section on a graph that was already permanently frozen.
Source
Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Graph.java:1541
@SuppressWarnings({"all", "try"})
public EconomicMap<Node, Node> addDuplicates(Iterable<? extends Node> newNodes, final Graph oldGraph, int estimatedNodeCount, DuplicationReplacement replacements, boolean applyGVN) {
try (DebugCloseable s = DuplicateGraph.start(getDebug())) {
return NodeClass.addGraphDuplicate(this, oldGraph, estimatedNodeCount, newNodes, replacements, applyGVN);
}
}
public boolean isFrozen() {
return freezeState != FreezeState.Unfrozen;
}
public void freeze() {
this.freezeState = FreezeState.DeepFreeze;
}
public void temporaryFreeze() {
if (this.freezeState == FreezeState.DeepFreeze) {
throw new GraalError("Graph was permanetly frozen.");
}
this.freezeState = FreezeState.TemporaryFreeze;
}
public void unfreeze() {
if (this.freezeState == FreezeState.DeepFreeze) {
throw new GraalError("Graph was permanetly frozen.");
}
this.freezeState = FreezeState.Unfrozen;
}
}
View on GitHub (pinned to a66e9ccd1d)
Solutions
- Check graph.isFrozen() (or inspect freezeState) before calling temporaryFreeze() and skip the temporary-freeze path for frozen graphs.
- Reorder the pipeline so verification/iteration that needs temporaryFreeze() runs before the permanent freeze() call.
- If you own the freeze, delay freeze() until after all verification passes have completed.
- Clone the graph (graph.copy()) if you must run mutating or freezing operations on an already deep-frozen instance.
Example fix
// before
graph.temporaryFreeze(); // throws if DeepFreeze
// after
if (!graph.isFrozen()) {
graph.temporaryFreeze();
} Defensive patterns
Strategy: validation
Validate before calling
if (graph.isFrozen()) { /* graph is at least temporarily frozen; inspect further or skip */ }
// Graal exposes isFrozen(); to distinguish DeepFreeze you must track who called freeze()
if (!graph.isFrozen()) {
graph.temporaryFreeze();
} Prevention
- Treat freeze() as irreversible: audit every call site in your pipeline and guarantee no temporaryFreeze()/unfreeze() runs after it.
- In shared utilities, guard temporary-freeze sections with isFrozen() checks instead of assuming an unfrozen graph.
- Never run verification helpers against cached graphs; clone them first.
When it happens
Trigger: Calling graph.temporaryFreeze() at any point after graph.freeze() has already been invoked; e.g. a verification or iteration helper that temporary-freezes runs against a graph that a prior phase (such as caching/installing the graph) already deep-froze. Also nested/temporary-freeze helpers invoked on shared cached graphs.
Common situations: Custom compilation phases or graph verifiers that run late in the pipeline, after the graph was frozen for caching. Re-running a debug/verify utility over a graph obtained from a cache. New plugin code that assumes graphs are always mutable.
Related errors
- NodeBitMap was modified between the calls to hasNext() and n
- accessing node id in %s across %d graph compression%s
- this node is not alive:
- unknown verbosity:
- Could not load Graal NodeClass TYPE field for
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/63342630ab9d2607.
Report an issue: GitHub.