oracle/graal · critical · TooManyDeoptimizationsError

deopt taken too many times: {} {}

Error message

deopt taken too many times: {} {}

What it means

ForceDeoptSpeculationPhase exists to detect deoptimization loops: when a forced deopt (ForceDeoptValueNode, enabled by the -Dgraal.Deoptimize* testing options) fires again on recompiled code, the speculation fails and the graph is recompiled without it. After getMaximumDeoptCount() failures the phase throws TooManyDeoptimizationsError (ForceDeoptSpeculationPhase.java:150) to break the cycle.

Source

Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/ForceDeoptSpeculationPhase.java:150

        for (int i = 0; i < getMaximumDeoptCount(graph); i++) {
            SpeculationLog.SpeculationReason reason = VERIFY_SPECULATION.createSpeculationReason(signature.getSignature(), signature.getId(deopt), i);
            if (graph.getSpeculationLog().maySpeculate(reason)) {
                return graph.getSpeculationLog().speculate(reason);
            }
        }
        throw reportTooManySpeculationFailures(deopt);
    }

    @SuppressWarnings("unused")
    protected int getMaximumDeoptCount(StructuredGraph graph) {
        return recompileCount;
    }

    /**
     * Report a deopt cycle.
     */
    protected GraalError reportTooManySpeculationFailures(ValueNode deopt) {
        throw new TooManyDeoptimizationsError("deopt taken too many times: " + deopt + " " + getDeoptSummary(deopt.graph().getProfilingInfo()));
    }
}

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Remove or narrow the -Dgraal.Deoptimize* option so the affected method is no longer forced to deopt
  2. If this is an intentional stress test, accept the error or raise the recompile/deopt budget option used by getMaximumDeoptCount
  3. Check DeoptimizeMethodFilter/DeoptimizeOnly filters for a pattern that unintentionally matches the failing method

Example fix

# before
java -Dgraal.DeoptimizeALot=true MyApp

# after
java -Dgraal.DeoptimizeALot=true -Dgraal.DeoptimizeOnly=com.foo.StableBench.myApp MyApp
Defensive patterns

Strategy: try-catch

Try / catch

// when programmatically compiling with force-deopt options
try {
    compiled = compile(options);
} catch (TooManyDeoptimizationsError e) {
    // deopt cycle confirmed: drop the force-deopt option and recompile
    options = optionsWithout(DeoptimizeOptions);
    compiled = compile(options);
}

Prevention

When it happens

Trigger: Compiling with a force-deopt testing option (e.g., -Dgraal.DeoptimizeALot, DeoptimizeMethodFilter/DeoptimizeOnly, or playground-style deopt injection) where the marked code keeps deoptimizing across recompilations until the recompile budget is exhausted.

Common situations: Stress-testing configurations left enabled in benchmarks; a method filter that keeps matching hot methods whose deopts never stabilize; intentionally cyclic deopt tests that exceed the configured maximum.

Related errors


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