rust-lang/rust · critical
unexpected nested goal in `relate`: {p:?}
Error message
unexpected nested goal in `relate`: {p:?} What it means
EvalCtxt::relate_and_add_goals calls the delegate's relate(), which returns nested goals; only Subtype, Projection (ClauseKind::Projection), and WellFormed goals are valid here. Any other PredicateKind triggers unreachable! because the type-relation pipeline is not designed to ingest arbitrary goals (e.g. Trait, RegionOutlives, ConstEquate).
Source
Thrown at compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs:1254
#[instrument(level = "trace", skip(self, param_env), ret)]
pub(super) fn relate<T: Relate<I>>(
&mut self,
param_env: I::ParamEnv,
lhs: T,
variance: ty::Variance,
rhs: T,
) -> Result<(), NoSolutionOrRerunNonErased> {
let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?;
for &goal in goals.iter() {
let source = match goal.predicate.kind().skip_binder() {
ty::PredicateKind::Subtype { .. }
| ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) => {
GoalSource::TypeRelating
}
// FIXME(-Znext-solver=coinductive): should these WF goals also be unproductive?
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => GoalSource::Misc,
p => unreachable!("unexpected nested goal in `relate`: {p:?}"),
};
self.add_goal(source, goal)?;
}
Ok(())
}
/// Equates two values returning the nested goals without adding them
/// to the nested goals of the `EvalCtxt`.
///
/// If possible, try using `eq` instead which automatically handles nested
/// goals correctly.
#[instrument(level = "trace", skip(self, param_env), ret)]
pub(super) fn eq_and_get_goals<T: Relate<I>>(
&self,
param_env: I::ParamEnv,
lhs: T,
rhs: T,
) -> Result<Vec<Goal<I, I::Predicate>>, NoSolution> {View on GitHub (pinned to 22057b88b0)
Solutions
- File a rustc ICE report with the {p:?} predicate printed by the panic.
- Inspect the delegate's relate implementation for the backend in use and confirm it only emits Subtype/Projection/WellFormed nested goals.
- Work around by disabling -Znext-solver.
- Bisect changes to the delegate's TypeRelating/Generalizer code that may have started emitting extra goal kinds.
Defensive patterns
Strategy: validation
Validate before calling
// Relate must not produce nested goals. Audit user code that calls traits whose
// associated items impose additional bounds during a relate step.
fn related_traits_introduce_nested_goals(item: &TraitItem) -> bool {
item.bounds.iter().any(|b| matches!(b, Bound::Trait(_)))
}
// run in a `xshell`-driven lint over the crate before `cargo build` Type guard
trait RelateFlat: Sized {}
impl<T> RelateFlat for T where T: Copy {}
// narrow relate operations to types that cannot carry nested goals Try / catch
use std::panic::{catch_unwind, AssertUnwindSafe};
let r = catch_unwind(AssertUnwindSafe(|| relate(a, b, variance)));
match r { Ok(()) => (), Err(_) => log::warn!("nested relate goal; deferring to legacy solver") } Prevention
- Avoid associated-type bounds (`T: Trait<Assoc: Bound>`) inside generic `where` clauses used by relate-heavy code paths.
- Split complex trait relations into multiple, simpler relations so no single relate step spawns a nested obligation.
- Reduce usage of higher-ranked trait bounds (`for<'a> T: Trait<'a>`) — these are the most common nested-goal source.
When it happens
Trigger: Reached when SolverDelegate::relate (invoked at compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs:1245) yields a nested goal whose kind is not Subtype, Clause(Projection), or Clause(WellFormed). Typically caused by a delegate implementation (rustc vs chalk vs external) emitting an unexpected goal kind.
Common situations: ICE encountered during type relation (subtyping/equating/coercion) under -Znext-solver. Almost always a bug in the delegate glue that bridges the infcx to the new solver, not user code.
Related errors
- this never happens at the root, we're never in erased mode h
- unexpected orig_value: {ty:?}
- unexpected orig_value: {ct:?}
- ConstEquate should not be emitted when `-Znext-solver` is ac
- Params should have been canonicalized to placeholders
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/db651aa25639c8d1.json.
Report an issue: GitHub.