{"id":"da8227ff8808d03d","repo":"rust-lang/rust","slug":"this-never-happens-at-the-root-we-re-never-in-era","errorCode":null,"errorMessage":"this never happens at the root, we're never in erased mode here","messagePattern":"this never happens at the root, we're never in erased mode here","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs","lineNumber":258,"sourceCode":"        // No need to try the fast path if stalled_on is `None`, since we already try the fast path\n        // immediately when adding new goals. If we didn't check `stalled_on` here we'd be trying\n        // the fast path twice for some goals.\n        if stalled_on.is_some()\n            && let Some(res) = compute_goal_fast_path_cold(self, goal, span)\n        {\n            return Ok(res);\n        }\n\n        let mut result = EvalCtxt::enter_root(self, self.cx().recursion_limit(), span, |ecx| {\n            ecx.evaluate_goal_no_fast_paths(GoalSource::Misc, goal)\n        });\n        maybe_evaluate_root_goal_with_higher_recursion_limit(self, goal, span, &mut result);\n\n        match result {\n            Ok(i) => Ok(i),\n            Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution)) => Err(NoSolution),\n            Err(NoSolutionOrRerunNonErased::RerunNonErased(_)) => {\n                unreachable!(\"this never happens at the root, we're never in erased mode here\");\n            }\n        }\n    }\n\n    #[instrument(level = \"debug\", skip(self), ret)]\n    fn root_goal_may_hold_opaque_types_jank(\n        &self,\n        goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,\n    ) -> bool {\n        self.probe(|| {\n            EvalCtxt::enter_root(self, self.cx().recursion_limit(), I::Span::dummy(), |ecx| {\n                ecx.evaluate_goal(GoalSource::Misc, goal, None)\n            })\n            .is_ok_and(|r| match r.certainty {\n                Certainty::Yes => true,\n                Certainty::Maybe(MaybeInfo {\n                    cause: _,\n                    opaque_types_jank,","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs#L240-L276","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["File a rustc issue with the -Znext-solver ICE and the full backtrace; this is a compiler bug, not user error.","If running a locally built compiler, bisect recent changes to evaluate_root_goal / enter_root / NoSolutionOrRerunNonErased handling.","Work around by disabling -Znext-solver (or -Znext-solver=coherence for coherence-only) until the invariant is restored.","Ensure nested goals always handle RerunNonErased before returning to the root, so the variant cannot propagate into enter_root."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before invoking rustc/cargo, assert the next-solver is NOT enabled for crates that\n// rely on erased/abstract root goals. Run as a build-check script.\nfn solver_mode_safe() -> bool {\n    let flags = std::env::var(\"RUSTFLAGS\").unwrap_or_default();\n    let cargo_flags = std::env::var(\"CARGO_ENCODED_RUSTFLAGS\").unwrap_or_default();\n    !(flags.contains(\"next-solver\") || cargo_flags.contains(\"next-solver\"))\n}\n#[test]\nfn assert_no_next_solver_at_root() { assert!(solver_mode_safe()); }","typeGuard":null,"tryCatchPattern":"// Compiling programmatically? Isolate the compiler call so an ICE cannot abort the host.\nuse std::panic::{catch_unwind, AssertUnwindSafe};\nlet outcome = catch_unwind(AssertUnwindSafe(|| {\n    // crate::my_proc_macro::expand_root(...) or rustc invocation\n}));\nif outcome.is_err() { /* report ICE, keep host alive */ }","preventionTips":["Pin to a stable rustc toolchain; `-Znext-solver` is nightly-only and reflows invariants frequently.","Do not enable the next solver project-wide; gate it behind a per-crate profile so root-level goals keep using the legacy solver.","Keep a `rust-toolchain.toml` committed so CI never picks a bleeding-edge compiler that re-introduces the bug.","Run `cargo build` with `RUST_BACKTRACE=1` only for diagnosis, never as a normal flow — it masks nothing and adds noise."],"tags":["rust","rustc","trait-solver","ice","next-solver","internal-invariant"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}