rust-lang/rust · critical
trying to decode `DefIndex` outside the context of a `DefId`
Error message
trying to decode `DefIndex` outside the context of a `DefId`
What it means
`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`.
Source
Thrown at compiler/rustc_middle/src/query/on_disk_cache.rs:693
|this| Symbol::intern(this.read_str()),
|opaque| Symbol::intern(opaque.read_str()),
)
}
fn decode_byte_symbol(&mut self) -> ByteSymbol {
self.decode_symbol_or_byte_symbol(
ByteSymbol::new,
|this| ByteSymbol::intern(this.read_byte_str()),
|opaque| ByteSymbol::intern(opaque.read_byte_str()),
)
}
// This impl makes sure that we get a runtime error when we try decode a
// `DefIndex` that is not contained in a `DefId`. Such a case would be problematic
// because we would not know how to transform the `DefIndex` to the current
// context.
fn decode_def_index(&mut self) -> DefIndex {
panic!("trying to decode `DefIndex` outside the context of a `DefId`")
}
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx UnordSet<LocalDefId> {
#[inline]
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
RefDecodable::decode(d)
}
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
for &'tcx UnordMap<DefId, ty::EarlyBinder<'tcx, Ty<'tcx>>>
{
#[inline]
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
RefDecodable::decode(d)
}
}View on GitHub (pinned to 22057b88b0)
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>`.
Example fix
// before — bare DefIndex persisted (panics on decode)
#[derive(Encodable, Decodable)]
struct CachedItemRef {
index: DefIndex, // ambiguous across sessions
}
// after — store a DefId, which the cache decodes via DefPathHash
#[derive(Encodable, Decodable)]
struct CachedItemRef {
def_id: DefId, // re-mapped correctly on load
} Defensive patterns
Strategy: fallback
Try / catch
// Decoding a DefIndex outside a DefId context means the cache's DefIndex->DefPathHash
// table is missing or stale. No caller-side pre-check exists; fall back to a clean build.
use std::process::Command;
fn build_clean_fallback(dir: &str) -> std::io::Result<std::process::ExitStatus> {
let s = Command::new("cargo").args(["build"]).current_dir(dir).status()?;
if s.success() { return Ok(s); }
let _ = Command::new("cargo").args(["clean"]).current_dir(dir).status();
Command::new("cargo").arg("build").current_dir(dir).status()
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- cannot decode `AttrId` with `CacheDecoder`
- Incremental cache file size overflowed u64.
- failed to lookup `SourceFile` in new context
- Bad hash {:?} (map {:?})
- Failed to convert DefPathHash {def_path_hash:?}
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/9a560c080d136603.json.
Report an issue: GitHub.