rust-lang/rust · critical
Error: trying to record dependency on DepNode {dep_node} in
Error message
Error: trying to record dependency on DepNode {dep_node} in a context that does not allow it (e.g. during query deserialization). The most common case of recording a dependency on a DepNode `foo` is when the corresponding query `foo` is invoked. Invoking queries is not allowed as part of loading something from the incremental on-disk cache. See <https://github.com/rust-lang/rust/pull/91919>. What it means
Internal compiler error (ICE) from panic_on_forbidden_read (compiler/rustc_middle/src/dep_graph/graph.rs:1446), reached via DepGraph::read_index when the current task's dependency-tracking ref is TaskDepsRef::Forbid. That state is used while deserializing/loading values from the incremental on-disk cache, where recording a new query dependency would create a cycle or a non-reproducible graph. The message names the offending DepNode and points at PR #91919 which introduced the forbid context.
Source
Thrown at compiler/rustc_middle/src/dep_graph/graph.rs:1446
// corresponds to `dep_node_index`, but that's OK since we are about
// to ICE anyway.
let mut dep_node = None;
// First try to find the dep node among those that already existed in the
// previous session and has been marked green
for prev_index in data.colors.values.indices() {
if data.colors.current(prev_index) == Some(dep_node_index) {
dep_node = Some(*data.previous.index_to_node(prev_index));
break;
}
}
let dep_node = dep_node.map_or_else(
|| format!("with index {:?}", dep_node_index),
|dep_node| format!("`{:?}`", dep_node),
);
panic!(
"Error: trying to record dependency on DepNode {dep_node} in a \
context that does not allow it (e.g. during query deserialization). \
The most common case of recording a dependency on a DepNode `foo` is \
when the corresponding query `foo` is invoked. Invoking queries is not \
allowed as part of loading something from the incremental on-disk cache. \
See <https://github.com/rust-lang/rust/pull/91919>."
)
}
impl<'tcx> TyCtxt<'tcx> {
/// Return whether this kind always require evaluation.
#[inline(always)]
fn is_eval_always(self, kind: DepKind) -> bool {
self.dep_kind_vtable(kind).is_eval_always
}
}
View on GitHub (pinned to 22057b88b0)
Solutions
- Report the ICE to the rustc team with the DepNode name and a reproducer; this is a compiler-internal invariant violation, not user code.
- If you are writing a custom query provider, ensure it does not call other tcx queries during decode/deserialize paths — read from the cached DepNode instead.
- Disable incremental compilation (-C incremental=no) or wipe the incremental cache directory to rule out cache corruption causing a different code path.
- Bisect across nightly rustc versions to find the commit that introduced the query call inside the forbidden context (PR #91919 is the reference point).
Defensive patterns
Strategy: fallback
Validate before calling
// No pre-call validation is possible: the error fires deep inside
// query deserialization from the incremental cache. Mitigate by
// disabling incremental compilation for the affected crate.
fn build_cmd_no_incremental() -> std::process::Command {
let mut cmd = std::process::Command::new("cargo");
cmd.args(["build", "--release", "-C", "incremental=no"]);
cmd.env_remove("CARGO_INCREMENTAL");
cmd
} Try / catch
// For tool authors driving rustc as a library via rustc_interface::run_compiler,
// isolate the compiler callback in catch_unwind so an ICE does not tear down
// the host process.
use std::panic::{catch_unwind, AssertUnwindSafe};
let result = catch_unwind(AssertUnwindSafe(|| {
rustc_interface::run_compiler(config, |tcx| {
// ... perform queries that may trigger incremental cache loading ...
})
}));
match result {
Ok(value) => /* use value */ { let _ = value; }
Err(payload) => {
eprintln!("rustc ICE during incremental cache load; falling back to clean build");
// Delete target/<profile>/incremental and retry once without -Zincremental
}
} Prevention
- Disable incremental compilation (CARGO_INCREMENTAL=0 or -C incremental=no) in CI and release builds
- Delete the target/<profile>/incremental directory when switching toolchains or updating macros
- Report the ICE with the rustc version and the panic backtrace to the rust-lang/rust issue tracker
- Avoid mixing nightly and stable toolchains on the same target directory
When it happens
Trigger: A query is invoked (transitively) from inside the on-disk cache loading path, e.g. decoding a SerializedDepGraph entry, decoding a query result, or running an eval_always query while TaskDepsRef is Forbid. Concretely, read_index(dep_node_index) is called while the thread-local TaskDepsRef equals Forbid.
Common situations: Compiler bugs where a deserializer/decoder calls into tcx.<query>(...) instead of reading the cached value; custom rustc query providers that invoke other queries during deserialization; regressions after refactors that move query calls into the decode path.
Related errors
- Error: A dep graph node ({kind:?}) does not have an unique i
- dep node {prev_index:?} is unexpectedly red
- RUST_FORBID_DEP_GRAPH_EDGE invalid: {}
- counting sort fills every slot of a kind's range
- unsupported integer: {self:?}
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/425140e2b643a440.json.
Report an issue: GitHub.