{"id":"2b15d1814c10da93","repo":"rust-lang/rust","slug":"could-not-find-work-product-for-cgu","errorCode":null,"errorMessage":"Could not find work-product for CGU `{}`","messagePattern":"Could not find work-product for CGU `(.+?)`","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"compiler/rustc_middle/src/mono.rs","lineNumber":521,"sourceCode":"        // Items are never zero-sized, so if we have items the estimate must be\n        // non-zero, unless we forgot to call `compute_size_estimate` first.\n        assert!(self.items.is_empty() || self.size_estimate != 0);\n        self.size_estimate\n    }\n\n    pub fn contains_item(&self, item: &MonoItem<'tcx>) -> bool {\n        self.items().contains_key(item)\n    }\n\n    pub fn work_product_id(&self) -> WorkProductId {\n        WorkProductId::from_cgu_name(self.name().as_str())\n    }\n\n    pub fn previous_work_product(&self, tcx: TyCtxt<'_>) -> WorkProduct {\n        let work_product_id = self.work_product_id();\n        tcx.dep_graph\n            .previous_work_product(&work_product_id)\n            .unwrap_or_else(|| panic!(\"Could not find work-product for CGU `{}`\", self.name()))\n    }\n\n    pub fn items_in_deterministic_order(\n        &self,\n        tcx: TyCtxt<'tcx>,\n    ) -> Vec<(MonoItem<'tcx>, MonoItemData)> {\n        // The codegen tests rely on items being process in the same order as\n        // they appear in the file, so for local items, we sort by span first\n        #[derive(PartialEq, Eq, PartialOrd, Ord)]\n        struct ItemSortKey<'tcx>(Option<Span>, SymbolName<'tcx>);\n\n        // We only want to take HirIds of user-defines instances into account.\n        // The others don't matter for the codegen tests and can even make item\n        // order unstable.\n        fn local_item_id<'tcx>(item: MonoItem<'tcx>) -> Option<DefId> {\n            match item {\n                MonoItem::Fn(ref instance) => match instance.def {\n                    InstanceKind::Item(def) => def.as_local().map(|_| def),","sourceCodeStart":503,"sourceCodeEnd":539,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_middle/src/mono.rs#L503-L539","documentation":"`CodegenUnit::previous_work_product` (mono.rs:521) does a `.unwrap_or_else(|| panic!(...))` on the previous dep-graph's work product for this CGU's `WorkProductId`. The lookup should always succeed when incremental compilation is consistent: every CGU recorded in the current partition must have a matching entry produced in the prior session. A miss means the incremental dep graph and the current CGU set disagree—typically a stale or partially-overwritten `target/incremental` directory.","triggerScenarios":"Fires during incremental codegen when `tcx.dep_graph.previous_work_product(&work_product_id)` returns `None` for a CGU that the current run believes should have been cached. Commonly triggered by external mutation of `target/` between runs, a crashed prior compilation that left a half-written incremental DB, or a `cargo` invocation that changed the codegen-unit layout (e.g. different `codegen-units`, panic strategy, or `-C prefer-dynamic`) without invalidating the cache.","commonSituations":"Developers hit this after killing a build mid-flight (`Ctrl-C` during codegen), after a disk-full / crash, after switching toolchains without `cargo clean`, after editing `Cargo.toml`'s `[profile]` codegen settings, or after a CI runner restored a stale incremental cache that doesn't match the current source tree. Also seen when `RUSTC_WRAPPER` (e.g. sccache) returns a cached artifact that disagrees with the local incremental DB.","solutions":["Delete the incremental cache and rebuild: `cargo clean && cargo build` (fastest reliable fix).","If a full clean is too costly, remove only `target/<triple>/incremental/` (and `target/debug/incremental/`).","Disable incremental compilation for the run: `CARGO_INCREMENTAL=0 cargo build` or pass `-C incremental=no`.","Stop wiping/reusing `target/` across toolchain switches; pin one toolchain per workspace (rustup override) and clean when switching.","Stop committing or rsyncing `target/` between machines; treat it as machine-scoped, not portable."],"exampleFix":"# before (mismatched incremental state)\n$ cargo build   # prior run crashed; target/incremental half-written\n$ cargo build   # panic: Could not find work-product for CGU `...`\n\n# after\n$ rm -rf target/debug/incremental target/<triple>/incremental\n$ cargo build   # rebuilds incremental DB cleanly","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Missing work-product for a CGU usually means the incremental cache is stale/corrupt.\nuse std::process::Command;\nfn build_without_incremental(dir: &str) -> std::io::Result<std::process::ExitStatus> {\n    // First try: incremental on (fast path).\n    let s1 = Command::new(\"cargo\").args([\"build\"]).current_dir(dir).status()?;\n    if s1.success() { return Ok(s1); }\n    // Fallback: wipe incremental artifacts and rebuild with incremental off.\n    Command::new(\"cargo\").args([\"clean\"]).current_dir(dir).status()?;\n    Command::new(\"cargo\")\n        .args([\"build\", \"--config\", \"profile.dev.incremental=false\"])\n        .current_dir(dir)\n        .status()\n}","preventionTips":["Disable incremental compilation in CI: `CARGO_INCREMENTAL=0`.","Clean `target/` after switching branches that change crate graphs.","Never share a `target/` directory across different toolchain versions.","If pinning nightly, record the exact commit hash so CGU layout stays stable."],"tags":["rustc","incremental-compilation","codegen-unit","work-product","cache-corruption"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}