neoclide/coc.nvim · warning
${uri} changed before apply edit
Error message
${uri} changed before apply edit What it means
LSP TextDocumentEdit changes are version-checked: each change specifies the document version the edit was computed against. When coc's local document version no longer matches (or a versioned edit targets a document not loaded), applying the edit is refused to prevent corrupting the buffer with stale edits.
Source
Thrown at src/core/files.ts:634
public async redoWorkspaceEdit(): Promise<void> {
let { editState } = this
if (!editState || editState.applied) {
void this.window.showWarningMessage(`No workspace edit to redo`)
return
}
this.editState = undefined
await this.applyEdit(editState.edit)
}
public validateChanges(documentChanges: ReadonlyArray<DocumentChange>): void {
let { documents } = this
for (let change of documentChanges) {
if (TextDocumentEdit.is(change)) {
let { uri, version } = change.textDocument
let doc = documents.getDocument(uri)
if (typeof version === 'number' && version > 0) {
if (!doc) throw errors.notLoaded(uri)
if (doc.version != version) throw new Error(`${uri} changed before apply edit`)
} else if (!doc && !isFile(uri)) {
throw errors.badScheme(uri)
}
} else if (CreateFile.is(change) || DeleteFile.is(change)) {
if (!isFile(change.uri)) throw errors.badScheme(change.uri)
} else if (RenameFile.is(change)) {
if (!isFile(change.oldUri) || !isFile(change.newUri)) {
throw errors.badScheme(change.oldUri)
}
}
}
}
public async findFiles(include: GlobPattern, exclude?: GlobPattern | null, maxResults?: number, token?: CancellationToken): Promise<URI[]> {
let folders = this.workspaceFolderControl.workspaceFolders
if (token?.isCancellationRequested || !folders.length || maxResults === 0) return []
maxResults = maxResults ?? Infinity
let roots = folders.map(o => URI.parse(o.uri).fsPath)View on GitHub (pinned to 50e974d969)
Solutions
- Re-trigger the code action/format after the buffer settles so the server computes edits against the current version
- Avoid editing the buffer while a long refactor/format is in flight
- Update the language server; stale-version races are often server bugs
- Retry the operation; the buffer itself is left untouched (operation is atomic before any change)
Example fix
// before
const edit = await session.codeAction(...)
await workspace.applyEdit(edit) // may throw if buffer changed
// after
const edit = await session.codeAction(...)
try { await workspace.applyEdit(edit) } catch { notify('Buffer changed, please retry') } Defensive patterns
Strategy: retry
Validate before calling
// compare versions before applying an LSP edit
const doc = workspace.getDocument(editUri)
const versioned = edit.documentChanges?.find(c => c.textDocument?.uri === editUri)
if (doc && versioned && typeof versioned.textDocument.version === 'number'
&& doc.version !== versioned.textDocument.version) {
return notify('Stale edit; re-run the action')
} Type guard
const isCurrentEdit = (doc, change) => !change || typeof change.textDocument?.version !== 'number' || change.textDocument.version <= 0 || doc?.version === change.textDocument.version
Try / catch
try {
await workspace.applyEdit(edit)
} catch (e) {
if (String(e.message).includes('changed before apply edit')) notify('Buffer changed; retry the action')
else throw e
} Prevention
- Don't edit the buffer while a code action/format request is in flight
- Re-request actions instead of caching WorkspaceEdits
- Keep language servers updated; stale-version races are often server bugs
- Apply edits promptly after receiving them
When it happens
Trigger: A language server returns WorkspaceEdit with textDocument.version set while the user edited/saved the buffer since the request started; edits applied after slow code actions or formatting on a rapidly changing buffer; document closed and reopened between request and response.
Common situations: Race between typing and applying code actions/format from LSP; long-running refactor while user keeps editing; async formatting on save racing with further changes.
Related errors
- Unable to getCallHierarchyItem at current position
- Action "${action.title}" is disabled: ${action.disabled.reas
- Format provider not found for buffer: ${doc.bufnr}
- ${id} provider not found for current buffer, your language s
- Inlay hint provider not found for current document
AI-assisted analysis of neoclide/coc.nvim@50e974d969 (2026-08-31).
Data as JSON: /api/errors/78e57083e5bd30ed.
Report an issue: GitHub.