rust-lang/rust-analyzer · error
bad tag: {other}
Error message
bad tag: {other} What it means
While converting a flat legacy-protocol token stream back into `proc_macro_srv::TokenTree`s, the parser dispatches on a tag word identifying the token-tree variant (group, ident, literal, punctuation). An unrecognized tag means the buffer is corrupt or encoded by an incompatible protocol version; the reader panics with `bad tag: {other}`.
Source
Thrown at crates/proc-macro-api/src/legacy_protocol/msg/flat.rs:844
let text = self.text[repr.text as usize].as_str();
let (is_raw, text) = if self.version >= EXTENDED_LEAF_DATA {
(
if repr.is_raw { tt::IdentIsRaw::Yes } else { tt::IdentIsRaw::No },
text,
)
} else {
tt::IdentIsRaw::split_from_symbol(text)
};
s.push(
tt::Leaf::Ident(tt::Ident {
sym: Symbol::intern(text),
span: read_span(repr.id),
is_raw,
})
.into(),
)
}
other => panic!("bad tag: {other}"),
}
}
res[i] = Some((delimiter, s));
}
let (delimiter, mut res) = res[0].take().unwrap();
res.insert(0, tt::TokenTree::Subtree(tt::Subtree { delimiter, len: res.len() as u32 }));
tt::TopSubtree::from_serialized(res)
}
}
#[cfg(feature = "in-rust-tree")]
impl<T: SpanTransformer> Reader<'_, T> {
pub(crate) fn read_tokenstream(
self,
span_join: impl Fn(T::Span, T::Span) -> T::Span,
) -> proc_macro_srv::TokenStream<T::Span> {
let mut res: Vec<Option<proc_macro_srv::Group<T::Span>>> = vec![None; self.subtree.len()];View on GitHub (pinned to e8f7e90aa3)
Solutions
- Rebuild the proc-macro server to match the rust-analyzer/protocol version
- Check that buffer offsets are computed with the same word sizes and layout as the writer
- Validate all tag values fall in the known set before decoding, or migrate to the current protocol
Example fix
// before
let words = &flat[i..i + 3]; // wrong stride -> reads payload as tag
// after
let words = &flat[i..i + token_tree_word_count(tag)];
assert!(tag <= MAX_KNOWN_TAG, "unknown token tree tag {tag}"); Defensive patterns
Strategy: validation
Validate before calling
fn valid_token_tree_tag(tag: u32) -> bool { tag <= 3 } Type guard
fn is_known_tt_tag(tag: u32) -> bool {
matches!(tag, 0..=3)
} Prevention
- Match word strides and offsets exactly with the writer's layout
- Rebuild proc-macro server binaries with the matching rust-analyzer revision
- Sanity-check tag words before dispatch during decoding
- Migrate from the legacy flat protocol to the current one
When it happens
Trigger: Decoding a `SubtreeRepr`'s token stream where a token-tree tag word is not one of the known variant discriminators.
Common situations: Proc-macro server built against a different rust-analyzer revision than the client; hand-patched flat buffers; offset arithmetic errors that read a payload word (e.g. a span or length) as a tag.
Related errors
- bad kind {other}
- bad spacing {other}
- We explicitly do not provide canonicalization API, as that i
- profiler already started
- profiler failed to start
AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03).
Data as JSON: /api/errors/22875adc62745348.
Report an issue: GitHub.