rust-lang/rust · critical

this never happens at the root, we're never in erased mode h

Error message

this never happens at the root, we're never in erased mode here

What it means

Internal compiler panic in the next trait solver's root-goal evaluator. After EvalCtxt::enter_root runs a goal at the recursion limit, the inner result is pattern-matched; the RerunNonErased variant is declared unreachable because root evaluation never executes in 'erased mode' (that mode only exists for nested/canonicalized sub-goals in the search graph). Hitting it means a solver refactor broke the invariant that the root entry point is always non-erased.

Source

Thrown at compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs:258

        // No need to try the fast path if stalled_on is `None`, since we already try the fast path
        // immediately when adding new goals. If we didn't check `stalled_on` here we'd be trying
        // the fast path twice for some goals.
        if stalled_on.is_some()
            && let Some(res) = compute_goal_fast_path_cold(self, goal, span)
        {
            return Ok(res);
        }

        let mut result = EvalCtxt::enter_root(self, self.cx().recursion_limit(), span, |ecx| {
            ecx.evaluate_goal_no_fast_paths(GoalSource::Misc, goal)
        });
        maybe_evaluate_root_goal_with_higher_recursion_limit(self, goal, span, &mut result);

        match result {
            Ok(i) => Ok(i),
            Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution)) => Err(NoSolution),
            Err(NoSolutionOrRerunNonErased::RerunNonErased(_)) => {
                unreachable!("this never happens at the root, we're never in erased mode here");
            }
        }
    }

    #[instrument(level = "debug", skip(self), ret)]
    fn root_goal_may_hold_opaque_types_jank(
        &self,
        goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
    ) -> bool {
        self.probe(|| {
            EvalCtxt::enter_root(self, self.cx().recursion_limit(), I::Span::dummy(), |ecx| {
                ecx.evaluate_goal(GoalSource::Misc, goal, None)
            })
            .is_ok_and(|r| match r.certainty {
                Certainty::Yes => true,
                Certainty::Maybe(MaybeInfo {
                    cause: _,
                    opaque_types_jank,

View on GitHub (pinned to 22057b88b0)

Solutions

  1. File a rustc issue with the -Znext-solver ICE and the full backtrace; this is a compiler bug, not user error.
  2. If running a locally built compiler, bisect recent changes to evaluate_root_goal / enter_root / NoSolutionOrRerunNonErased handling.
  3. Work around by disabling -Znext-solver (or -Znext-solver=coherence for coherence-only) until the invariant is restored.
  4. Ensure nested goals always handle RerunNonErased before returning to the root, so the variant cannot propagate into enter_root.
Defensive patterns

Strategy: validation

Validate before calling

// Before invoking rustc/cargo, assert the next-solver is NOT enabled for crates that
// rely on erased/abstract root goals. Run as a build-check script.
fn solver_mode_safe() -> bool {
    let flags = std::env::var("RUSTFLAGS").unwrap_or_default();
    let cargo_flags = std::env::var("CARGO_ENCODED_RUSTFLAGS").unwrap_or_default();
    !(flags.contains("next-solver") || cargo_flags.contains("next-solver"))
}
#[test]
fn assert_no_next_solver_at_root() { assert!(solver_mode_safe()); }

Try / catch

// Compiling programmatically? Isolate the compiler call so an ICE cannot abort the host.
use std::panic::{catch_unwind, AssertUnwindSafe};
let outcome = catch_unwind(AssertUnwindSafe(|| {
    // crate::my_proc_macro::expand_root(...) or rustc invocation
}));
if outcome.is_err() { /* report ICE, keep host alive */ }

Prevention

When it happens

Trigger: Reached if EvalCtxt::enter_root returns Err(NoSolutionOrRerunNonErased::RerunNonErased(_)) from evaluate_root_goal in compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs:257. This requires an inner evaluate_goal_no_fast_paths call to signal a non-erased rerun that propagates all the way up through enter_root instead of being handled at a nested level.

Common situations: Almost always a regression introduced while refactoring the solver's erased/non-erased evaluation paths (e.g. trait-system-refactor-initiative changes). End users only hit it as an ICE on arbitrary crates; it is not caused by user source code.

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/da8227ff8808d03d.json. Report an issue: GitHub.