can1357/oh-my-pi · error · ToolError
overlapping LSP edits: ${formatRange(earlier)} conflicts wit
Error message
overlapping LSP edits: ${formatRange(earlier)} conflicts with ${formatRange(later)}; LSP produced inconsistent edits What it means
After sorting edits bottom-up and collapsing byte-identical duplicates, the validator walks adjacent pairs: each earlier (later-in-document) edit's range end must not extend past the next edit's start. If ranges overlap, applying bottom-up would clobber offsets and corrupt the file, so a ToolError names the two conflicting ranges.
Source
Thrown at packages/coding-agent/src/lsp/edits.ts:122
})
.map(entry => entry.edit);
const unique: TextEdit[] = [];
for (const edit of sorted) {
const prev = unique[unique.length - 1];
if (prev && !isEmptyRange(edit.range) && rangesEqual(prev.range, edit.range) && prev.newText === edit.newText) {
continue;
}
unique.push(edit);
}
// Detect overlapping ranges: in reverse-sorted order, each edit's start
// must be >= the next edit's end. If not, the edits would clobber each other
// once applied bottom-up.
for (let i = 0; i < unique.length - 1; i++) {
const later = unique[i].range;
const earlier = unique[i + 1].range;
if (comparePosition(earlier.end, later.start) > 0) {
throw new ToolError(
`overlapping LSP edits: ${formatRange(earlier)} conflicts with ${formatRange(later)}; LSP produced inconsistent edits`,
);
}
}
return unique;
}
/**
* Flatten a WorkspaceEdit's text edits into a Map<uri, TextEdit[]>.
* Resource operations (create/rename/delete) are ignored — callers handle them separately.
*/
export function flattenWorkspaceTextEdits(edit: WorkspaceEdit): Map<string, TextEdit[]> {
const out = new Map<string, TextEdit[]>();
const push = (uri: string, edits: TextEdit[]) => {
if (edits.length === 0) return;
const prev = out.get(uri);
if (prev) prev.push(...edits);View on GitHub (pinned to 9690622007)
Solutions
- Request only one code action at a time instead of merging multiple actions' edits
- Fix or update the language server producing overlapping ranges
- Split application: apply each edit set to a fresh document state sequentially
Example fix
// before: merging edits from two actions sortAndValidateTextEdits([...actionAEdits, ...actionBEdits]); // after: apply sequentially applyEdits(actionAEdits); applyEdits(refreshEdits(actionBEdits));
Defensive patterns
Strategy: validation
Validate before calling
function rangesOverlap(a, b) {
const cmp = (p, q) => p.line - q.line || p.character - q.character;
return !(cmp(a.end, b.start) <= 0 || cmp(b.end, a.start) <= 0);
}
for (let i = 0; i < edits.length; i++)
for (let j = i + 1; j < edits.length; j++)
if (rangesOverlap(edits[i].range, edits[j].range)) throw new Error('server produced overlapping edits'); Try / catch
try {
const sorted = sortAndValidateTextEdits(edits);
} catch (err) {
if (err.message.startsWith('overlapping LSP edits:')) {
// fall back to applying edits one action at a time, re-querying between batches
}
throw err;
} Prevention
- Apply one code action's edits at a time rather than merging multiple actions
- Keep language servers updated — overlapping edits usually indicate a server bug
- Deduplicate identical edits before validation
When it happens
Trigger: A server returns two text edits whose ranges overlap after dedup (e.g. two code actions both covering the same lines, or a malformed computeEdit output); sortAndValidateTextEdits detects comparePosition(earlier.end, later.start) > 0.
Common situations: Server bugs producing inconsistent edits; combining edits from multiple code actions on overlapping regions; renamed/refactored server emitting stale ranges.
Related errors
- snippet-formatted LSP edits are unsupported
- Operations ${previous.operationNumber} and ${current.operati
- Server "${targetServer}" returned no content for "${uri}".
- Failed to stop LSP server(s) with superseded configuration:
- LSP configuration was superseded during reload: ${config.com
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/039c214af425a100.
Report an issue: GitHub.