{"record":{"id":"94222d94858707fc","repo":"charmbracelet/crush","slug":"failed-to-apply-document-change-w","errorCode":null,"errorMessage":"failed to apply document change: %w","messagePattern":"failed to apply document change: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/lsp/util/edit.go","lineNumber":280,"sourceCode":"\t}\n\treturn len(lineText)\n}\n\n// ApplyWorkspaceEdit applies the given WorkspaceEdit to the filesystem.\n// The encoding parameter specifies the position encoding used by the LSP server\n// (UTF8, UTF16, or UTF32). This affects how character offsets are interpreted.\nfunc ApplyWorkspaceEdit(edit protocol.WorkspaceEdit, encoding powernap.OffsetEncoding) error {\n\t// Handle Changes field\n\tfor uri, textEdits := range edit.Changes {\n\t\tif err := applyTextEdits(uri, textEdits, encoding); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to apply text edits: %w\", err)\n\t\t}\n\t}\n\n\t// Handle DocumentChanges field\n\tfor _, change := range edit.DocumentChanges {\n\t\tif err := applyDocumentChange(change, encoding); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to apply document change: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// rangesOverlap checks if two LSP ranges overlap.\n// Per the LSP specification, ranges are half-open intervals [start, end),\n// so adjacent ranges where one's end equals another's start do NOT overlap.\n// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#range\nfunc rangesOverlap(r1, r2 protocol.Range) bool {\n\tif r1.Start.Line > r2.End.Line || r2.Start.Line > r1.End.Line {\n\t\treturn false\n\t}\n\tif r1.Start.Line == r2.End.Line && r1.Start.Character >= r2.End.Character {\n\t\treturn false\n\t}\n\tif r2.Start.Line == r1.End.Line && r2.Start.Character >= r1.End.Character {","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/lsp/util/edit.go#L262-L298","documentation":"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.","triggerScenarios":"Any applyDocumentChange failure for a DocumentChanges element: invalid edit type, target-file-exists on rename, os.Rename failure, or applyTextEdits failure inside a TextDocumentEdit.","commonSituations":"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.","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"],"exampleFix":"// before\nif err := ApplyWorkspaceEdit(edit, enc); err != nil {\n    return err\n}\n// after\nif err := ApplyWorkspaceEdit(edit, enc); err != nil {\n    root := err\n    for errors.Unwrap(root) != nil {\n        root = errors.Unwrap(root)\n    }\n    log.Printf(\"workspace edit failed: %v (cause: %v)\", err, root)\n    return root\n}","handlingStrategy":"try-catch","validationCode":"func validateWorkspaceEdit(edit protocol.WorkspaceEdit, openDocs map[string]struct{}) error {\n    for _, ch := range edit.DocumentChanges {\n        if ch.TextDocumentEdit != nil {\n            if _, ok := openDocs[string(ch.TextDocumentEdit.TextDocument.URI)]; !ok {\n                return fmt.Errorf(\"doc not open: %s\", ch.TextDocumentEdit.TextDocument.URI)\n            }\n        }\n        if ch.RenameFile != nil {\n            if ch.RenameFile.Options == nil || !ch.RenameFile.Options.Overwrite {\n                if _, err := os.Stat(string(ch.RenameFile.NewURI)); err == nil {\n                    return fmt.Errorf(\"rename target exists: %s\", ch.RenameFile.NewURI)\n                }\n            }\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := ApplyWorkspaceEdit(edit, enc); err != nil {\n    root := err\n    for errors.Unwrap(root) != nil { root = errors.Unwrap(root) }\n    switch {\n    case strings.Contains(fmt.Sprint(root), \"not exist\"):\n        // stale document: refresh and retry\n    case strings.Contains(err.Error(), \"document change\"):\n        log.Printf(\"entry failed: %v\", err)\n    }\n}","preventionTips":["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"],"tags":["lsp","workspace-edit","document-change"],"backgroundTag":"workspace-edit-apply-failed","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}