astral-sh/ruff · error
Patch span `{bigger:?}` is beyond the end of buffer `{source
Error message
Patch span `{bigger:?}` is beyond the end of buffer `{source_len}` What it means
The patch (suggestion/diff) rendering path validates every patch span against the snippet source before splicing. Like annotations, an end up to source.len() + 1 is allowed ('patching one past the last character'); beyond that it panics with the patch range and buffer length. It means the patch spans were computed against different (usually older or longer) text than the source being rendered.
Source
Thrown at crates/ruff_annotate_snippets/src/renderer/source_map.rs:443
}
}
// If high index is None
if hi_opt.is_none() {
buf.push('\n');
}
}
}
let source_len = self.source.len();
if let Some(bigger) = patches.iter().find_map(|x| {
// Allow patching one past the last character in the source.
if source_len + 1 < x.span.end {
Some(&x.span)
} else {
None
}
}) {
panic!("Patch span `{bigger:?}` is beyond the end of buffer `{source_len}`")
}
// Assumption: all spans are in the same file, and all spans
// are disjoint. Sort in ascending order.
patches.sort_by_key(|p| p.span.start);
// Find the bounding span.
let (lo, hi) = if fold {
let lo = patches
.iter()
.map(|p| p.span.clone())
.min_by_key(|s| s.start)?;
let hi = patches
.iter()
.map(|p| p.span.clone())
.max_by_key(|s| s.end)?;
(lo, hi)
} else {View on GitHub (pinned to d1087a4b9e)
Solutions
- Recompute patch spans from the exact text passed as the snippet source.
- Clamp or drop patches whose end exceeds source.len() + 1 before rendering.
- In watch-mode flows, discard cached suggestions when the underlying file changes.
Example fix
// before: patch range computed against an older, longer version of the file let patch = Patch::new(stale_range, replacement); // stale_range.end > source.len() // after: derive the range from the text being rendered let patch = Patch::new(current_range, replacement); // current_range.end <= source.len()
Defensive patterns
Strategy: validation
Validate before calling
fn patches_within(source: &str, patches: &[Patch<'_>]) -> bool {
let len = source.len();
patches.iter().all(|p| p.span.end <= len + 1 && p.span.start <= p.span.end)
}
// before rendering a suggestion:
debug_assert!(patches_within(snippet_source, patches)); Try / catch
let out = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| renderer.render(&report)))
.unwrap_or_else(|_| render_without_suggestion(&report)); // drop the diff, keep the message Prevention
- Compute patch spans from the exact text used for rendering, after any edits settle.
- Invalidate cached suggestions when the underlying file changes.
- Keep expected patch ranges in fixtures generated from the fixture text, not typed by hand.
When it happens
Trigger: Rendering a snippet with a suggestion whose patch spans came from a different version of the file: edits landed between diagnostic creation and rendering, or test fixtures were updated while expected ranges stayed stale.
Common situations: LSP/watch-mode rendering after document edits; tests with hardcoded patch offsets; transformations that splice the source without recomputing ranges.
Related errors
- Annotation range `{bigger:?}` is beyond the end of buffer `{
- 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/f839b13df3515aab.
Report an issue: GitHub.