charmbracelet/crush · error
invalid URI: %w
Error message
invalid URI: %w
What it means
applyTextEdits converts a protocol.DocumentURI to a filesystem path via uri.Path() before reading the file and applying edits. If the URI is not a valid file-scheme URI (no extractable path), the error is wrapped as "invalid URI" and no edits are applied. It is reached from applyDocumentChange and ApplyWorkspaceEdit when handling server-initiated edits.
Source
Thrown at internal/lsp/util/edit.go:17
package util
import (
"bytes"
"fmt"
"os"
"sort"
"strings"
powernap "github.com/charmbracelet/x/powernap/pkg/lsp"
"github.com/charmbracelet/x/powernap/pkg/lsp/protocol"
)
func applyTextEdits(uri protocol.DocumentURI, edits []protocol.TextEdit, encoding powernap.OffsetEncoding) error {
path, err := uri.Path()
if err != nil {
return fmt.Errorf("invalid URI: %w", err)
}
// Read the file content
content, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("failed to read file: %w", err)
}
// Detect line ending style
var lineEnding string
if bytes.Contains(content, []byte("\r\n")) {
lineEnding = "\r\n"
} else {
lineEnding = "\n"
}
// Track if file ends with a newline
endsWithNewline := len(content) > 0 && bytes.HasSuffix(content, []byte(lineEnding))View on GitHub (pinned to 7944b8e522)
Solutions
- Filter workspace edit URIs and skip any whose scheme is not file:// before applying.
- Check the server's edit payload (log the URI) to identify non-file resources.
- Configure/upgrade the LSP server so edits only reference real file URIs.
- Convert the resource to a file-backed document (save untitled buffers) before applying edits.
Example fix
// before
for _, edit := range wsEdit.Changes {
applyTextEdits(edit.Uri, edit.Edits, enc) // may be non-file URI
}
// after
if !strings.HasPrefix(string(edit.Uri), "file://") {
continue // skip non-file URIs
}
applyTextEdits(edit.Uri, edit.Edits, enc) Defensive patterns
Strategy: type-guard
Validate before calling
u, err := url.Parse(string(uri))
if err != nil || u.Scheme != "file" {
return fmt.Errorf("skipping non-file URI: %s", uri)
} Type guard
func isFileURI(uri protocol.DocumentURI) bool {
u, err := url.Parse(string(uri))
return err == nil && u.Scheme == "file"
} Try / catch
if err := applyWorkspaceEdit(ctx, wsEdit); err != nil {
if strings.Contains(err.Error(), "invalid URI") {
slog.Warn("Workspace edit contained a non-file URI; skipped", "error", err)
return nil
}
return err
} Prevention
- Sanitize all server-provided URIs for file scheme before applying edits.
- Keep the LSP server updated; untitled/virtual-document edits are often server bugs.
- Log raw workspace-edit payloads during integration to catch URI anomalies early.
When it happens
Trigger: applyTextEdits called (via applyDocumentChange or ApplyWorkspaceEdit) with a URI whose .Path() fails — e.g. an unscheme:// URI, a malformed URI from the server, or a URI for a non-file resource the client cannot map to disk.
Common situations: Server returns workspace edits referencing virtual/unsaved documents; URI strings copied from other tooling without file:// scheme; server bug emitting non-file URIs (e.g. untitled: buffers) in edits; version mismatch where the server encodes URIs unexpectedly.
Related errors
- 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
- invalid edit type: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/7ec077cf295a3968.
Report an issue: GitHub.