{"id":"9a560c080d136603","repo":"rust-lang/rust","slug":"trying-to-decode-defindex-outside-the-context-of","errorCode":null,"errorMessage":"trying to decode `DefIndex` outside the context of a `DefId`","messagePattern":"trying to decode `DefIndex` outside the context of a `DefId`","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"compiler/rustc_middle/src/query/on_disk_cache.rs","lineNumber":693,"sourceCode":"            |this| Symbol::intern(this.read_str()),\n            |opaque| Symbol::intern(opaque.read_str()),\n        )\n    }\n\n    fn decode_byte_symbol(&mut self) -> ByteSymbol {\n        self.decode_symbol_or_byte_symbol(\n            ByteSymbol::new,\n            |this| ByteSymbol::intern(this.read_byte_str()),\n            |opaque| ByteSymbol::intern(opaque.read_byte_str()),\n        )\n    }\n\n    // This impl makes sure that we get a runtime error when we try decode a\n    // `DefIndex` that is not contained in a `DefId`. Such a case would be problematic\n    // because we would not know how to transform the `DefIndex` to the current\n    // context.\n    fn decode_def_index(&mut self) -> DefIndex {\n        panic!(\"trying to decode `DefIndex` outside the context of a `DefId`\")\n    }\n}\n\nimpl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx UnordSet<LocalDefId> {\n    #[inline]\n    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {\n        RefDecodable::decode(d)\n    }\n}\n\nimpl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>\n    for &'tcx UnordMap<DefId, ty::EarlyBinder<'tcx, Ty<'tcx>>>\n{\n    #[inline]\n    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {\n        RefDecodable::decode(d)\n    }\n}","sourceCodeStart":675,"sourceCodeEnd":711,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_middle/src/query/on_disk_cache.rs#L675-L711","documentation":"`CacheDecoder::decode_def_index` (on_disk_cache.rs:693) is a deliberate, unconditional `panic!(\"trying to decode DefIndex outside the context of a DefId\")`. A bare `DefIndex` is only meaningful relative to a specific `CrateNum`, and both can change between sessions, so the cache encodes `DefId`s as `DefPathHash` and re-maps them on load. Decoding a raw `DefIndex` is therefore ambiguous and always rejected. Reaching it means some type persisted a standalone `DefIndex` instead of wrapping it in a `DefId`.","triggerScenarios":"Triggered when a type containing a bare `DefIndex` field (rather than a `DefId`) is `derive`d as `Decodable<CacheDecoder>` and that type appears in a query result written to the incremental cache; the derived impl calls `decode_def_index`, which panics unconditionally.","commonSituations":"Encountered by rustc contributors and tooling authors who add a new persisted type and inadvertently include a `DefIndex` (e.g. a `LocalDefFileIndex`-like helper, or a copy of a `DefId`'s index field) without converting it to a `DefId`/`DefPathHash`. End users of released rustc never see it; if they do, it's a compiler regression to report.","solutions":["Report to rust-lang/rust with the failing crate and `rustc -vV`; the persisted type should store a `DefId` (decoded via `DefPathHash`), not a bare `DefIndex`.","In-tree fix: change the offending field to `DefId` (or `LocalDefId`/`DefPathHash`) so the decoder re-maps it across sessions.","If deriving `Decodable`, audit every field for `DefIndex` and replace or wrap it; re-run `x.py test compiler/rustc_middle`.","As a quick verification, grep `compiler/` for `DefIndex` inside any struct whose impl list includes `Decodable<CacheDecoder>`."],"exampleFix":"// before — bare DefIndex persisted (panics on decode)\n#[derive(Encodable, Decodable)]\nstruct CachedItemRef {\n    index: DefIndex, // ambiguous across sessions\n}\n\n// after — store a DefId, which the cache decodes via DefPathHash\n#[derive(Encodable, Decodable)]\nstruct CachedItemRef {\n    def_id: DefId, // re-mapped correctly on load\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Decoding a DefIndex outside a DefId context means the cache's DefIndex->DefPathHash\n// table is missing or stale. No caller-side pre-check exists; fall back to a clean build.\nuse std::process::Command;\nfn build_clean_fallback(dir: &str) -> std::io::Result<std::process::ExitStatus> {\n    let s = Command::new(\"cargo\").args([\"build\"]).current_dir(dir).status()?;\n    if s.success() { return Ok(s); }\n    let _ = Command::new(\"cargo\").args([\"clean\"]).current_dir(dir).status();\n    Command::new(\"cargo\").arg(\"build\").current_dir(dir).status()\n}","preventionTips":["Clean after changing `lib.rs`/`mod.rs` structure that shifts DefIndex ordering.","Never share incremental caches across workspace configurations (different features/members).","After a toolchain bump, wipe `target/` before any incremental build.","If it persists on a clean tree, report as an ICE — the DefId/DefIndex table is internal to rustc."],"tags":["rustc","incremental-compilation","on-disk-cache","defindex","defid","serialization","internal-compiler-error"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}