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

  1. Check graph.isFrozen() (or inspect freezeState) before calling temporaryFreeze() and skip the temporary-freeze path for frozen graphs.
  2. Reorder the pipeline so verification/iteration that needs temporaryFreeze() runs before the permanent freeze() call.
  3. If you own the freeze, delay freeze() until after all verification passes have completed.
  4. 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

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


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/63342630ab9d2607. Report an issue: GitHub.