rust-lang/rust-analyzer · error
bad spacing {other}
Error message
bad spacing {other} What it means
`PunctRepr::read` decodes punctuation spacing over the legacy proc-macro protocol: tag 0 maps to `tt::Spacing::Alone` and 1 to `tt::Spacing::Joint`. Any other value cannot be represented, so the decoder panics with `bad spacing {other}`.
Source
Thrown at crates/proc-macro-api/src/legacy_protocol/msg/flat.rs:427
}
fn read_with_kind([id, text, kind, suffix]: [u32; 4]) -> LiteralRepr {
LiteralRepr { id: SpanId(id), text, kind: kind as u16, suffix }
}
}
impl PunctRepr {
fn write(self) -> [u32; 3] {
let spacing = match self.spacing {
tt::Spacing::Alone | tt::Spacing::JointHidden => 0,
tt::Spacing::Joint => 1,
};
[self.id.0, self.char as u32, spacing]
}
fn read([id, char, spacing]: [u32; 3]) -> PunctRepr {
let spacing = match spacing {
0 => tt::Spacing::Alone,
1 => tt::Spacing::Joint,
other => panic!("bad spacing {other}"),
};
PunctRepr { id: SpanId(id), char: char.try_into().unwrap(), spacing }
}
}
impl IdentRepr {
fn write(self) -> [u32; 2] {
[self.id.0, self.text]
}
fn read(data: [u32; 2]) -> IdentRepr {
IdentRepr { id: SpanId(data[0]), text: data[1], is_raw: false }
}
fn write_with_rawness(self) -> [u32; 3] {
[self.id.0, self.text, self.is_raw as u32]
}
fn read_with_rawness([id, text, is_raw]: [u32; 3]) -> IdentRepr {
IdentRepr { id: SpanId(id), text, is_raw: is_raw == 1 }
}View on GitHub (pinned to e8f7e90aa3)
Solutions
- Align the proc-macro server version with rust-analyzer so both sides use the same spacing encoding
- Fix the writer to emit only 0 (Alone) or 1 (Joint)
- Validate spacing tags before decoding or upgrade off the legacy protocol
Example fix
// before
let spacing = 2; // invalid legacy encoding
// after
let spacing = match punct.spacing {
tt::Spacing::Alone => 0,
tt::Spacing::Joint => 1,
}; Defensive patterns
Strategy: validation
Validate before calling
fn valid_spacing_tag(tag: u32) -> bool { tag <= 1 } Type guard
fn is_known_spacing(tag: u32) -> bool {
matches!(tag, 0 | 1)
} Prevention
- Encode spacing as exactly 0 (Alone) or 1 (Joint) on the write side
- Keep protocol encodings synchronized between server and client
- Check the 3-word [id, char, spacing] layout before decoding
- Avoid carrying spacing values from other token encodings into the flat protocol
When it happens
Trigger: `PunctRepr::read` receives a spacing field other than 0 or 1 from the flat 3-word [id, char, spacing] representation.
Common situations: Mismatched proc-macro server/protocol versions where the spacing encoding changed; corrupted token buffers; a writer bug encoding spacing as a boolean-like value other than 0/1 (e.g. 2 for JointIsolated in other encodings).
Related errors
- bad kind {other}
- bad tag: {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/0e0fc48df89f4e39.
Report an issue: GitHub.