rust-lang/rust · critical
forbidden edge {:?} -> {:?} created
Error message
forbidden edge {:?} -> {:?} created What it means
Only under `debug_assertions`: when a task records a read edge in the dep graph (graph.rs:538), rustc checks it against a declared `forbidden_edge` set. Creating an edge the dep-graph ordering rules forbid is an internal invariant violation, so the debug build panics with the offending source→target pair. Release builds skip the check.
Source
Thrown at compiler/rustc_middle/src/dep_graph/graph.rs:538
panic_on_forbidden_read(data, dep_node_index)
}
};
let task_deps = &mut *task_deps;
if cfg!(debug_assertions) {
data.current.total_read_count.fetch_add(1, Ordering::Relaxed);
}
let new_read = task_deps.reads.insert(dep_node_index, &data.read_recorder_pool);
if new_read {
#[cfg(debug_assertions)]
{
if let Some(target) = task_deps.node
&& let Some(ref forbidden_edge) = data.current.forbidden_edge
{
let src = forbidden_edge.index_to_node.lock()[&dep_node_index];
if forbidden_edge.test(&src, &target) {
panic!("forbidden edge {:?} -> {:?} created", src, target)
}
}
}
} else if cfg!(debug_assertions) {
data.current.total_duplicate_read_count.fetch_add(1, Ordering::Relaxed);
}
})
}
}
/// This encodes a side effect by creating a node with an unique index and associating
/// it with the node, for use in the next session.
#[inline]
pub fn record_diagnostic<'tcx>(&self, tcx: TyCtxt<'tcx>, diagnostic: &DiagInner) {
if let Some(ref data) = self.data {
read_deps(|task_deps| match task_deps {
TaskDepsRef::EvalAlways | TaskDepsRef::Ignore => return,
TaskDepsRef::Forbid | TaskDepsRef::Allow(..) => {View on GitHub (pinned to 22057b88b0)
Solutions
- If you are not developing rustc, switch to a release/stable rustc — the assertion is debug-only and the underlying behavior is otherwise allowed.
- If developing rustc, inspect the src/target dep-node kinds of the reported edge and verify the query's TaskDeps/dep-graph ordering is correct.
- Reproduce minimally and file a rustc internal-compiler-error issue with the edge and the query call stack.
Defensive patterns
Strategy: validation
Validate before calling
// Before inserting a dependency edge, confirm the (from,to) pair is
// one the graph's policy actually permits.
fn assert_edge_allowed(
g: &DepGraph,
from: DepNodeIndex,
to: DepNodeIndex,
) -> Result<(), String> {
if g.is_edge_allowed(from, to) {
Ok(())
} else {
Err(format!("forbidden edge {:?} -> {:?}", from, to))
}
} Type guard
fn is_allowed_edge(g: &DepGraph, from: DepNodeIndex, to: DepNodeIndex) -> bool {
g.is_edge_allowed(from, to)
} Prevention
- Do not mix nodes from two different dep-graph instances; edges across graphs are forbidden by construction.
- Avoid hand-editing the dep graph; rely on the query system to create edges.
- If you observe this from a custom tool, double-check that task serialization preserves the graph identity.
When it happens
Trigger: Running a debug build of rustc (or a dev build with assertions on) where a query records a dependency the dep-graph model says must not exist — i.e. a compiler-internal bug in query dependency tracking. Never reached in release/user builds.
Common situations: Hacking on rustc itself with a debug build; running rustc tests under debug assertions; very rarely via a debug-built rustdoc or tool. End users on release builds never see it.
Related errors
- Cannot summarize when dependencies are not recorded.
- try_mark_previous_green() - forcing failed to set a color
- RUST_FORBID_DEP_GRAPH_EDGE invalid: {}
- Invalid DepKind {u}
- Query label {label} does not exist
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/06153050529c7436.json.
Report an issue: GitHub.