rust-lang/cargo · error

not currently active!?

Error message

not currently active!?

What it means

Internal debug-only invariant assertion in Cargo's dependency resolver (src/resolver/mod.rs:898). While combining conflict maps during backtracking, the resolver builds a new ConflictMap and then asserts every key in it is still an active package in the current ResolverContext via cx.is_active(c).expect("not currently active!?"). The whole block is wrapped in cfg!(debug_assertions), so it only fires in debug/test builds of cargo; in a release build the branch is dead and never executes. A panic here means the conflict-combining / parent-substitution logic recorded a conflict against a package that the resolver context no longer considers active.

Source

Thrown at src/resolver/mod.rs:898

                // A, B are both known bad states each that can never be activated.
                // A + B is redundant but can't be activated, as if
                // A + B is active then A is active and we know that is not ok.
                for (_, other) in &others {
                    con.extend(other.iter().map(|(&id, re)| (id, re.clone())));
                }
                // Now that we have this combined conflict, we can do a substitution:
                // A dep is equivalent to one of the things it can resolve to.
                // So we can remove all the things that it resolves to and replace with the parent.
                for (other_id, _) in &others {
                    con.remove(other_id);
                }
                con.insert(*critical_parent, backtrack_critical_reason);

                if cfg!(debug_assertions) {
                    // the entire point is to find an older conflict, so let's make sure we did
                    let new_age = con
                        .keys()
                        .map(|&c| cx.is_active(c).expect("not currently active!?"))
                        .max()
                        .unwrap();
                    assert!(
                        new_age < backtrack_critical_age,
                        "new_age {} < backtrack_critical_age {}",
                        new_age,
                        backtrack_critical_age
                    );
                }
                past_conflicting_activations.insert(dep, &con);
                return Some(con);
            }
        }
    }
    None
}

/// Returns Some of the largest item in the iterator.

View on GitHub (pinned to 0e07a15537)

Solutions

  1. Reproduce with a release cargo build (e.g. `cargo build --release` of cargo) - the assertion is compiled into a dead branch there and will not fire; if resolution succeeds, you have confirmed it is the debug invariant being overly strict, not a real misresolution.
  2. Reduce the failing Cargo.toml with `cargo repro` / manual minimization to the smallest dependency set that reproduces the panic and attach it to a rust-lang/cargo issue so the resolver bookkeeping bug can be fixed.
  3. On a debug build, bisect cargo commits around the resolver / backtracking changes to find which change broke the invariant.
  4. As a workaround for the graph itself, pin or loosen specific dependency versions so the conflict-combining path is not exercised.

Example fix

// before: debug cargo panics on a messy graph
//   RUSTFLAGS='' cargo run --build -j8   # dev profile => cfg!(debug_assertions) true
//   thread 'main' panicked at src/resolver/mod.rs:898: not currently active!?

// after: confirm with a release binary where the assertion is dead
//   cargo build --release
//   ./target/release/cargo build
// then report the minimized repro to rust-lang/cargo.
Defensive patterns

Strategy: fallback

Validate before calling

// Not guardable from caller code (internal resolver invariant).
// Pre-check that you are not on a debug cargo build before relying on resolution:
fn assert_release_cargo() {
    // cfg!(debug_assertions) is false => the failing branch at mod.rs:894-907 is dead.
    assert!(!cfg!(debug_assertions), "this graph trips a debug-only resolver assertion; use a release cargo");
}

Type guard

// No type-level guard: PackageId / ConflictMap are internal to cargo.
// Only narrowing available is 'is this a release binary?', which removes the panic site.

Try / catch

// Panics are not normally caught in cargo. If you embed cargo as a library,
// isolate the resolving thread and catch_unwind to degrade gracefully:
use std::panic;
let result = panic::catch_unwind(|| {
    // ... call into cargo's resolve ...
});
if result.is_err() {
    // fall back to a release cargo or a simplified manifest; do NOT silently retry unchanged.
}

Prevention

When it happens

Trigger: Running a debug build of cargo (or cargo's own test suite) against a dependency graph that forces the backtracking 'find an older conflict' optimization in find_candidate's sibling logic: multiple parents of a critical activation, where past_conflicting_activations.find(...) yields a combined conflict that, after substituting critical_parent, still references a package id whose is_active() returns None.

Common situations: Hacking on cargo itself with a dev build; running cargo resolver tests; a complex workspace with many conflicting semver requirements and yanked/publish-age-restricted crates that drive deep backtracking. Not reproducible with a stock release cargo from rustup.

Related errors


AI-assisted analysis of rust-lang/cargo@0e07a15537 (2026-08-06). Data as JSON: /data/errors/bc7d59411fb405bb.json. Report an issue: GitHub.