astral-sh/ruff · error
Annotation range `{bigger:?}` is beyond the end of buffer `{
Error message
Annotation range `{bigger:?}` is beyond the end of buffer `{source_len}` What it means
SourceMap::annotated_lines maps annotation ranges onto source lines before rendering. It validates every annotation's span end against source.len(), tolerating at most one past the last character (so EOF spans can highlight an insertion point); anything larger panics with the offending range and buffer length. The panic means the spans were computed against different text than the source string handed to the renderer.
Source
Thrown at crates/ruff_annotate_snippets/src/renderer/source_map.rs:185
lines
}
pub(crate) fn annotated_lines(
&self,
annotations: Vec<Annotation<'a>>,
fold: bool,
) -> (usize, Vec<AnnotatedLineInfo<'a>>) {
let source_len = self.source.len();
if let Some(bigger) = annotations.iter().find_map(|x| {
// Allow highlighting one past the last character in the source.
if source_len + 1 < x.span.end {
Some(&x.span)
} else {
None
}
}) {
panic!("Annotation range `{bigger:?}` is beyond the end of buffer `{source_len}`")
}
let mut annotated_line_infos = self
.lines
.iter()
.map(|info| AnnotatedLineInfo {
line: info.line,
line_index: info.line_index,
annotations: vec![],
keep: false,
})
.collect::<Vec<_>>();
let mut multiline_annotations = vec![];
for Annotation {
span,
label,
kind,View on GitHub (pinned to d1087a4b9e)
Solutions
- Derive both the source text and the annotation ranges from the same snapshot (e.g. the same SourceFile), so ends can never exceed its length.
- Clamp or drop annotations whose end exceeds source.len() + 1 before rendering.
- If diagnostics are rendered later than produced, invalidate or recompute spans on text-change notifications.
Example fix
// before: span from the full file, snippet built from a shorter string
let snippet = Snippet::source(&line_of_code)
.annotation(AnnotationKind::Primary.span(full_file_range)); // end beyond buffer
// after: translate the range into the snippet's own coordinates
let snippet = Snippet::source(&line_of_code)
.annotation(AnnotationKind::Primary.span(local_range)); // 0..line_of_code.len() Defensive patterns
Strategy: validation
Validate before calling
fn annotations_within(source: &str, anns: &[Annotation<'_>]) -> bool {
let len = source.len();
anns.iter().all(|a| a.span.end <= len + 1 && a.span.start <= a.span.end)
}
// before rendering:
debug_assert!(annotations_within(snippet_source, annotations)); Try / catch
let out = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| renderer.render(&report)))
.unwrap_or_else(|_| format!("{path}: {title}")); // fall back to a one-line diagnostic Prevention
- Derive snippet source and annotation ranges from the same SourceFile snapshot.
- In LSP/watchers, drop or recompute cached spans on text-change notifications.
- Compute ranges with source_text.find(...) in tests instead of hardcoding offsets.
When it happens
Trigger: Calling the renderer with a Snippet whose source is shorter than an annotation's span end: reusing byte ranges from one file while passing a truncated or different source string; stale spans from before the file was edited; hardcoded offsets in tests against an updated fixture.
Common situations: Long-running processes (LSP servers) rendering with spans cached from before a file change; building context snippets from sliced source; tests with fixed numeric ranges that rot when fixtures change; off-by-one at EOF.
Related errors
- Patch span `{bigger:?}` is beyond the end of buffer `{source
- Expected a Title
- unexpected annotation type: {annotation:?}
- Expected a ty `File`, found a ruff `SourceFile`
- should be set because `extract_if` only yields elements with
AI-assisted analysis of astral-sh/ruff@d1087a4b9e (2026-08-20).
Data as JSON: /api/errors/f8f2573e1f3539c0.
Report an issue: GitHub.