rust-lang/rust · critical

Attempted to encode LazyAttrTokenStream

Error message

Attempted to encode LazyAttrTokenStream

What it means

`panic!("Attempted to encode LazyAttrTokenStream")` is fired by the `Encodable` impl for `LazyAttrTokenStream`. The lazy stream holds parser-internal cursor state (snapshots, call counts, node replacements) that is intentionally non-serializable; it must be *forced* into a concrete `AttrTokenStream` before it can be encoded to incr-comp data or cached. The panic exists to catch serialization of un-forced lazy streams.

Source

Thrown at compiler/rustc_ast/src/tokenstream.rs:150

            break_last_token,
            node_replacements,
        }))
    }

    pub fn to_attr_token_stream(&self) -> AttrTokenStream {
        self.0.to_attr_token_stream()
    }
}

impl fmt::Debug for LazyAttrTokenStream {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "LazyAttrTokenStream({:?})", self.to_attr_token_stream())
    }
}

impl<S: SpanEncoder> Encodable<S> for LazyAttrTokenStream {
    fn encode(&self, _s: &mut S) {
        panic!("Attempted to encode LazyAttrTokenStream");
    }
}

impl<D: SpanDecoder> Decodable<D> for LazyAttrTokenStream {
    fn decode(_d: &mut D) -> Self {
        panic!("Attempted to decode LazyAttrTokenStream");
    }
}

impl StableHash for LazyAttrTokenStream {
    fn stable_hash<Hcx: StableHashCtxt>(&self, _hcx: &mut Hcx, _hasher: &mut StableHasher) {
        panic!("Attempted to compute stable hash for LazyAttrTokenStream");
    }
}

/// A token range within a `Parser`'s full token stream.
#[derive(Clone, Debug)]
pub struct ParserRange(pub Range<u32>);

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Call `.to_attr_token_stream()` (or otherwise force) the `LazyAttrTokenStream` into a concrete `AttrTokenStream` before storing it in any `Encodable` structure.
  2. Audit the call site in the backtrace (`RUST_BACKTRACE=1`) to find which field still holds a `LazyAttrTokenStream` at serialization time, and force it at construction.
  3. Add a unit test that round-trips the affected AST node through `Encodable`/`Decodable` to prevent regression.

Example fix

// before
attr_tokens: LazyAttrTokenStream::new(...)
// later: encode fails

// after
attr_tokens: lazy.to_attr_token_stream()  // forced before storage
Defensive patterns

Strategy: validation

Validate before calling

// LazyAttrTokenStream is intentionally non-Encodable.
// Materialize to a real stream before encoding:
let encodable: AttrTokenStream = lazy.to_attr_token_stream();
// then encode encodable instead

Type guard

fn is_lazy_stream<T>(_v: &T) -> bool { false } // types-other-than-LazyAttrTokenStream are safe

Prevention

When it happens

Trigger: Any `Encodable::encode` call (directly or via `rustc_serialize`, incremental compilation serialization, or query caching) on a value still typed as `LazyAttrTokenStream`. This happens when a token stream wasn't forced to `AttrTokenStream` before being placed in a serializable struct.

Common situations: Refactors that change when lazy streams are forced, regressions in attribute/macro token collection, or new query results that retain `LazyAttrTokenStream` past the parse phase. Typically surfaces as an ICE during incremental compilation or crate serialization.

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/01479b1be1cf4a96.json. Report an issue: GitHub.