{"id":"6338827037f6de60","repo":"rust-lang/rust","slug":"dep-node-prev-index-is-unexpectedly-red","errorCode":null,"errorMessage":"dep node {prev_index:?} is unexpectedly red","messagePattern":"dep node (.+?) is unexpectedly red","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"compiler/rustc_middle/src/dep_graph/serialized.rs","lineNumber":962,"sourceCode":"        colors: &DepNodeColorMap,\n        node: DepNode,\n        value_fingerprint: Fingerprint,\n        edges: &[DepNodeIndex],\n        is_green: bool,\n    ) -> DepNodeIndex {\n        let _prof_timer = self.profiler.generic_activity(\"incr_comp_encode_dep_graph\");\n        let node = NodeInfo { node, value_fingerprint, edges };\n\n        let mut local = self.status.local.borrow_mut();\n\n        let index = self.status.next_index(&mut *local);\n        let color = if is_green { DesiredColor::Green { index } } else { DesiredColor::Red };\n\n        // Use `try_set_color` to avoid racing when `send_promoted` is called concurrently\n        // on the same index.\n        match colors.try_set_color(prev_index, color) {\n            TrySetColorResult::Success => {}\n            TrySetColorResult::AlreadyRed => panic!(\"dep node {prev_index:?} is unexpectedly red\"),\n            TrySetColorResult::AlreadyGreen { index } => return index,\n        }\n\n        self.status.bump_index(&mut *local);\n        self.status.encode_node(index, &node, &self.retained_graph, &mut *local);\n        index\n    }\n\n    /// Encodes a node that was promoted from the previous graph. It reads the information directly\n    /// from the previous dep graph and expects all edges to already have a new dep node index\n    /// assigned.\n    ///\n    /// Tries to mark the dep node green, and returns Some if it is now green,\n    /// or None if had already been concurrently marked red.\n    #[inline]\n    pub(crate) fn send_promoted(\n        &self,\n        prev_index: SerializedDepNodeIndex,","sourceCodeStart":944,"sourceCodeEnd":980,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_middle/src/dep_graph/serialized.rs#L944-L980","documentation":"ICE in Encoder::send_and_color (compiler/rustc_middle/src/dep_graph/serialized.rs:962). When re-encoding a node that existed in the previous graph, the code calls colors.try_set_color(prev_index, ...) and expects Success or AlreadyGreen; AlreadyRed is treated as a bug because the caller already decided this node is green (is_green == true) but the color map says it is red. It indicates an inconsistency between the marking pass and the encoding pass, often a race during parallel red-green marking.","triggerScenarios":"try_set_color returns AlreadyRed while send_and_color was called with is_green=true. Typically happens under parallel query evaluation where two threads race to color the same SerializedDepNodeIndex and one marks it red (re-execute) while the other tries to mark it green (re-use).","commonSituations":"High-core / heavily parallel rustc builds stressing the red-green algorithm; races introduced by a refactor of DepNodeColorMap; corrupt previous-session colors loaded from a damaged incremental cache.","solutions":["Clear the incremental cache (target/**/incremental) and rebuild; the previous-session colors are the most likely source of the inconsistency.","Run a clean build with -C incremental=no to confirm the ICE disappears without incremental compilation.","If it reproduces on a clean build, report to the rustc team as a threading/race bug in DepNodeColorMap, including the prev_index from the message and the parallelism level."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// \"dep node is unexpectedly red\" is an incremental consistency\n// verification failure. No pre-call check exists; mitigate by\n// detecting a stale/corrupt cache and clearing it.\nfn cache_looks_stale(target: &std::path::Path) -> bool {\n    let inc = target.join(\"incremental\");\n    // Heuristic: incremental dir exists but was touched before the\n    // toolchain last changed.\n    if let Ok(meta) = std::fs::metadata(&inc) {\n        if let Ok(mtime) = meta.modified() {\n            return mtime < toolchain_install_time();\n        }\n    }\n    false\n}","typeGuard":null,"tryCatchPattern":"// Retry once after a cache wipe when this panic surfaces during\n// incremental verification.\nuse std::panic::{catch_unwind, AssertUnwindSafe};\n\nmatch catch_unwind(AssertUnwindSafe(|| compile_with_incremental(tcx))) {\n    Ok(()) => {}\n    Err(_) => {\n        std::fs::remove_dir_all(\"target/debug/incremental\").ok();\n        compile_without_incremental(tcx);\n    }\n}","preventionTips":["Drop the -Z incremental-verify-ich flag if it triggers false positives on your nightly","Keep a single toolchain per target directory; do not cross-compile with mismatched nightlies","Run cargo clean after major dependency or toolchain upgrades","Disable incremental compilation for long-running CI pipelines that may observe cache drift"],"tags":["rustc","incremental-compilation","dep-graph","race-condition","ice"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}