[ICE]: "did not expect successful goal when collecting ambiguity errors"
@ShoyuVanilla is already working on this.
Since Sep 11, 2026.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
We're hitting an ICE while running cargo doc in your CI.
The following is Claude-generated; it contains the steps to reproduce it and some analysis.
Summary
Since nightly-2026-09-08, cargo doc on the Zebra
workspace ICEs while documenting zebra-consensus. rustdoc's auto-trait/blanket-impl synthesis
calls InferCtxt::evaluate_obligation, which goes through
FulfillmentEngine<ScrubbedTraitError>::evaluate_obligations_error_on_ambiguity. A stalled
OutlivesClause(<Verifier as Service<BatchControl<Item>>>::Future, 'static) goal then re-evaluates
to Certainty::Yes, tripping the span_delayed_bug in
compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs:140.
This is rustdoc-only: cargo check on the same commit and the same toolchain succeeds.
Reproduced locally on 1.100.0-nightly (4aa1fbcf4 2026-09-08) as well as in CI.
Steps to reproduce
git init zebra-ice && cd zebra-ice
git remote add origin https://github.com/ZcashFoundation/zebra.git
git fetch --depth=1 origin abf397469356dd03f7e6321a33b41f0d98a20060
git checkout --detach FETCH_HEAD
# ICEs
cargo +nightly doc --no-deps -p zebra-consensus --all-features --document-private-items
# For contrast, this succeeds on the same toolchain and commit
cargo +nightly check -p zebra-consensus --all-features
abf397469356dd03f7e6321a33b41f0d98a20060 is a commit on Zebra's main; the failure reproduces on
current main too. Note that Zebra's rust-toolchain.toml pins a stable toolchain, so the
+nightly override is required.
Building the whole workspace, as our CI does, hits the same ICE:
cargo +nightly doc --no-deps --workspace --all-features --document-private-items
Zebra vendors a C++ dependency (rocksdb) via librocksdb-sys. On a host with GCC 15 the build
needs CXXFLAGS="-include cstdint"; this is unrelated to the ICE but is needed to get far enough
to hit it.
Public CI logs
The failure is reproducible in public CI, which runs the floating nightly channel:
- First failing run: https://github.com/ZcashFoundation/zebra/actions/runs/34270352093/job/102210133119
(rustc 1.100.0-nightly (cea272fa3 2026-09-07)) - Last passing run: https://github.com/ZcashFoundation/zebra/actions/runs/33929686834
(rustc 1.100.0-nightly (a69a63265 2026-09-03))
Meta
rustc 1.100.0-nightly (4aa1fbcf4 2026-09-08)
binary: rustc
commit-hash: 4aa1fbcf467cf38ce58abfa8eb9213a789c5381c
commit-date: 2026-09-08
host: x86_64-unknown-linux-gnu
release: 1.100.0-nightly
LLVM version: 23.1.1
Also reproduces on rustc 1.100.0-nightly (cea272fa3 2026-09-07).
Error output
12 delayed bugs are emitted, over 7 distinct goals. All of them are
OutlivesClause(<_ as tower_service::Service<_>>::Future, 'static):
error: internal compiler error: did not expect successful goal when collecting ambiguity errors for `Binder { value: OutlivesClause(Alias(No, Alias { kind: Projection { def_id: DefId(42:11 ~ tower_service[ee0b]::Service::Future) }, args: [primitives::ed25519::Verifier, tower_batch_control::BatchControl<primitives::ed25519::Item>], .. }), 'static), bound_vars: [] }`
The other six differ only in args:
[primitives::halo2::OrchardFallback, primitives::halo2::Item]
[primitives::halo2::Verifier, tower_batch_control::BatchControl<primitives::halo2::Item>]
[primitives::redjubjub::Verifier, tower_batch_control::BatchControl<primitives::redjubjub::Item>]
[primitives::redpallas::Verifier, tower_batch_control::BatchControl<primitives::redpallas::Item>]
[primitives::sapling::Verifier, tower_batch_control::BatchControl<primitives::sapling::Item>]
[script::Verifier, script::Request]
followed by (no special RUSTDOCFLAGS are involved — this is a plain cargo doc):
note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md
note: please make sure that you have updated to the latest nightly
note: rustc 1.100.0-nightly (cea272fa3 2026-09-07) running on x86_64-unknown-linux-gnu
note: compiler flags: --crate-type lib
note: some of the compiler flags provided by cargo are hidden
query stack during panic:
end of query stack
error: could not document `zebra-consensus`
Backtrace
= note: delayed at /rustc-dev/4aa1fbcf467cf38ce58abfa8eb9213a789c5381c/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs:140:29
0: <rustc_errors::DiagCtxtInner>::emit_diagnostic
1: <rustc_errors::DiagCtxtHandle>::emit_diagnostic
2: <rustc_span::ErrorGuaranteed as rustc_errors::diagnostic::EmissionGuarantee>::emit_producing_guarantee
3: <rustc_errors::DiagCtxtHandle>::span_delayed_bug::<rustc_span::span_encoding::Span, alloc::string::String>
4: rustc_trait_selection::solve::fulfill::collect_remaining_errors_impl::<rustc_infer::traits::engine::ScrubbedTraitError>
5: <rustc_trait_selection::traits::engine::FulfillmentEngine<rustc_infer::traits::engine::ScrubbedTraitError> as rustc_infer::traits::engine::TraitEngine<rustc_infer::traits::engine::ScrubbedTraitError>>::evaluate_obligations_error_on_ambiguity
6: <rustc_infer::infer::InferCtxt as rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt>::evaluate_obligation
7: rustdoc::clean::utils::synthesize_auto_trait_and_blanket_impls
8: <rustdoc::passes::collect_trait_impls::SyntheticImplCollector as rustdoc::visit::DocVisitor>::visit_item
9: <rustdoc::passes::collect_trait_impls::SyntheticImplCollector as rustdoc::visit::DocVisitor>::visit_item
10: <rustdoc::passes::collect_trait_impls::SyntheticImplCollector as rustdoc::visit::DocVisitor>::visit_item
11: <rustdoc::passes::collect_trait_impls::SyntheticImplCollector as rustdoc::visit::DocVisitor>::visit_item
12: <rustc_session::session::Session>::time::<rustdoc::clean::types::Crate, rustdoc::passes::run::{closure#0}>
13: rustdoc::core::run_global_ctxt
14: rustdoc::main_args::{closure#2}::{closure#0}
15: rustc_interface::interface::run_compiler::<(), rustdoc::main_args::{closure#2}>::{closure#2}
16: std::sys::backtrace::__rust_begin_short_backtrace::<rustc_interface::util::run_in_thread_with_globals<rustc_interface::util::run_in_thread_pool_with_globals<rustc_interface::interface::run_compiler<(), rustdoc::main_args::{closure#2}>::{closure#2}, ()>::{closure#0}, ()>::{closure#0}::{closure#0}, ()>
17: <std::thread::lifecycle::spawn_unchecked<rustc_interface::util::run_in_thread_with_globals<rustc_interface::util::run_in_thread_pool_with_globals<rustc_interface::interface::run_compiler<(), rustdoc::main_args::{closure#2}>::{closure#2}, ()>::{closure#0}, ()>::{closure#0}::{closure#0}, ()>::{closure#1} as core::ops::function::FnOnce<()>>::call_once::{shim:vtable#0}
18: <std::sys::thread::unix::Thread>::new::thread_start
19: <unknown>
20: <unknown>
The rustc-ice-*.txt file the diagnostic points at contains only the version and platform lines —
these are span_delayed_bugs rather than a panic, so there is no panic backtrace to attach beyond
the one above.
Suspected cause
Regression window from our CI, which tracks floating nightly:
| nightly channel | rustc | result |
|---|---|---|
nightly-2026-09-04 |
a69a63265 2026-09-03 |
ok |
nightly-2026-09-08 |
cea272fa3 2026-09-07 |
ICE |
nightly-2026-09-09 |
4aa1fbcf4 2026-09-08 |
ICE |
That window contains #162182 ("delay unexpected successful goal during ambiguity reporting",
merged as 29c965e): the last good nightly is an ancestor of 29c965e, and the first bad one is
77 commits after it.
Reading that diff, the mechanism looks like this. Before #162182, the re-evaluation of stalled
obligations lived in fulfillment_error_for_stalled, which is only reached from
FromSolverError::from_solver_error for FulfillmentError. ScrubbedTraitError has its own
FromSolverError impl that maps NextSolverError::Ambiguity straight to
ScrubbedTraitError::Ambiguity without re-evaluating, so rustdoc never took that path. #162182
moved the re-evaluation eagerly into collect_remaining_errors_impl, which is generic over the
error type and therefore now runs for ScrubbedTraitError too — which is exactly what frames 4-6
of the backtrace show.
If that reading is right, #162182 didn't introduce the underlying "stalled goal re-evaluates to
Certainty::Yes" condition; it made a new caller (rustdoc) able to observe it.
Shape of the triggering code
The goals all come from documenting zebra_consensus::primitives::*, which declare public statics
of roughly this shape (source):
pub static VERIFIER: Lazy<
Fallback<
Batch<Verifier, Item>,
ServiceFn<fn(Item) -> BoxFuture<'static, Result<(), BoxError>>>,
>,
> = Lazy::new(|| { /* ... */ });
where tower_batch_control::Batch stores the associated future in a channel
(source):
pub struct Batch<T, Request: RequestWeight>
where
T: Service<BatchControl<Request>>,
{
tx: mpsc::UnboundedSender<Message<Request, T::Future>>,
// ...
}
so auto-trait synthesis on Fallback<Batch<Verifier, Item>, _> has to prove
<Verifier as Service<BatchControl<Item>>>::Future: 'static.
I have not managed to reduce this to a standalone file — a hand-written skeleton with the same
struct shapes does not ICE, so something in the surrounding tower / tower-batch-control bounds
is needed to make the goal stall in the first place. Happy to run cargo-bisect-rustc or try
further minimization if that would help.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.