charmbracelet/crush · error
failed to apply document change: %w
Error message
failed to apply document change: %w
What it means
ApplyWorkspaceEdit wraps any error from applyDocumentChange (per-entry in WorkspaceEdit.DocumentChanges) as "failed to apply document change". DocumentChanges is the newer WorkspaceEdit shape that can include both TextDocumentEdit and RenameFile operations. This wrapper preserves the underlying cause via %w.
Source
Thrown at internal/lsp/util/edit.go:280
}
return len(lineText)
}
// ApplyWorkspaceEdit applies the given WorkspaceEdit to the filesystem.
// The encoding parameter specifies the position encoding used by the LSP server
// (UTF8, UTF16, or UTF32). This affects how character offsets are interpreted.
func ApplyWorkspaceEdit(edit protocol.WorkspaceEdit, encoding powernap.OffsetEncoding) error {
// Handle Changes field
for uri, textEdits := range edit.Changes {
if err := applyTextEdits(uri, textEdits, encoding); err != nil {
return fmt.Errorf("failed to apply text edits: %w", err)
}
}
// Handle DocumentChanges field
for _, change := range edit.DocumentChanges {
if err := applyDocumentChange(change, encoding); err != nil {
return fmt.Errorf("failed to apply document change: %w", err)
}
}
return nil
}
// rangesOverlap checks if two LSP ranges overlap.
// Per the LSP specification, ranges are half-open intervals [start, end),
// so adjacent ranges where one's end equals another's start do NOT overlap.
// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#range
func rangesOverlap(r1, r2 protocol.Range) bool {
if r1.Start.Line > r2.End.Line || r2.Start.Line > r1.End.Line {
return false
}
if r1.Start.Line == r2.End.Line && r1.Start.Character >= r2.End.Character {
return false
}
if r2.Start.Line == r1.End.Line && r2.Start.Character >= r1.End.Character {View on GitHub (pinned to 7944b8e522)
Solutions
- Unwrap with errors.Unwrap / %w chain to find the root cause (rename vs text edit)
- Validate all entries first (target paths, document URIs) before applying, to make application closer to atomic
- Ensure document versions match; refresh stale documents and re-request the edit
Example fix
// before
if err := ApplyWorkspaceEdit(edit, enc); err != nil {
return err
}
// after
if err := ApplyWorkspaceEdit(edit, enc); err != nil {
root := err
for errors.Unwrap(root) != nil {
root = errors.Unwrap(root)
}
log.Printf("workspace edit failed: %v (cause: %v)", err, root)
return root
} Defensive patterns
Strategy: try-catch
Validate before calling
func validateWorkspaceEdit(edit protocol.WorkspaceEdit, openDocs map[string]struct{}) error {
for _, ch := range edit.DocumentChanges {
if ch.TextDocumentEdit != nil {
if _, ok := openDocs[string(ch.TextDocumentEdit.TextDocument.URI)]; !ok {
return fmt.Errorf("doc not open: %s", ch.TextDocumentEdit.TextDocument.URI)
}
}
if ch.RenameFile != nil {
if ch.RenameFile.Options == nil || !ch.RenameFile.Options.Overwrite {
if _, err := os.Stat(string(ch.RenameFile.NewURI)); err == nil {
return fmt.Errorf("rename target exists: %s", ch.RenameFile.NewURI)
}
}
}
}
return nil
} Try / catch
if err := ApplyWorkspaceEdit(edit, enc); err != nil {
root := err
for errors.Unwrap(root) != nil { root = errors.Unwrap(root) }
switch {
case strings.Contains(fmt.Sprint(root), "not exist"):
// stale document: refresh and retry
case strings.Contains(err.Error(), "document change"):
log.Printf("entry failed: %v", err)
}
} Prevention
- Validate all DocumentChanges entries (URIs open, rename targets free) before applying
- Prefer DocumentChanges over Changes so version checks are available
- Unwrap the %w chain to identify which entry failed
When it happens
Trigger: Any applyDocumentChange failure for a DocumentChanges element: invalid edit type, target-file-exists on rename, os.Rename failure, or applyTextEdits failure inside a TextDocumentEdit.
Common situations: Rename/multi-file refactor operations from the server hitting one bad entry; a rename where the destination exists; encoding mismatch causing position errors; mixed operations where one entry references a stale document version.
Related errors
- invalid URI: %w
- failed to read file: %w
- overlapping edits detected between edit %d and %d
- failed to apply edit: %w
- target file already exists and overwrite is not allowed: %s
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/94222d94858707fc.
Report an issue: GitHub.