charmbracelet/crush · error
permission request failed: %w
Error message
permission request failed: %w
What it means
When an LSP rename targets a path outside the working directory, a permission request is created and submitted. If the permissions subsystem itself errors (store failure, context cancellation), the error is wrapped as 'permission request failed'. This is distinct from an explicit denial, which returns a permission-denied response instead.
Source
Thrown at internal/agent/tools/lsp_rename.go:71
edit, err := resolved.client.Rename(ctx, resolved.path, resolved.line, resolved.char, params.NewName)
if err != nil {
slog.Error("Failed to rename symbol", "error", err, "symbol", params.Symbol)
return fantasy.NewTextErrorResponse(fmt.Sprintf("rename failed: %s", err)), nil
}
if edit == nil {
return fantasy.NewTextResponse(fmt.Sprintf("No rename edits generated for symbol '%s'", params.Symbol)), nil
}
sessionID := GetSessionFromContext(ctx)
if sessionID != "" && permissions != nil {
granted, err := permissions.Request(ctx, permission.CreatePermissionRequest{
SessionID: sessionID,
ToolName: RenameToolName,
Description: fmt.Sprintf("Rename '%s' to '%s'", params.Symbol, params.NewName),
})
if err != nil {
return fantasy.ToolResponse{}, fmt.Errorf("permission request failed: %w", err)
}
if !granted {
return NewPermissionDeniedResponse(), nil
}
}
affectedFiles := collectAffectedFiles(edit)
if files != nil && sessionID != "" {
for _, path := range affectedFiles {
content, err := os.ReadFile(path)
if err != nil {
slog.Warn("Failed to read file for version tracking", "path", path, "error", err)
continue
}
if _, err := files.CreateVersion(ctx, sessionID, path, string(content)); err != nil {
slog.Warn("Failed to create file version", "path", path, "error", err)
}View on GitHub (pinned to 7944b8e522)
Solutions
- Inspect the wrapped %w error for the underlying cause.
- Ensure the SQLite database backing permissions is writable and not locked.
- Retry the rename; transient DB or context issues resolve on a fresh attempt.
- Keep the rename target inside the working directory to skip the permission path entirely.
Example fix
// before Rename(ctx, params) // db locked -> permission request failed // after // ensure no other process holds the DB lock, then retry Rename(ctx, params)
Defensive patterns
Strategy: try-catch
Validate before calling
// ensure DB-backed permission store reachable before tool call
if err := permissions.Ping(ctx); err != nil { return err } Type guard
null
Try / catch
_, err := renameTool(ctx, params)
if err != nil {
if strings.Contains(err.Error(), "permission request failed") {
// retry once after checking DB health / context cancellation
}
} Prevention
- Avoid canceling the context while a permission prompt is pending
- Keep SQLite DB healthy (no locks/corruption) for permission storage
- Prefer in-working-dir operations that skip permission requests
When it happens
Trigger: Invoking the LSP rename tool on an out-of-working-dir path while permissions.Request fails: DB (permission store) unavailable, context canceled mid-request, or a malformed session ID.
Common situations: Database locked or corrupted during permission persistence; user canceled the TUI prompt closing the context; running headless where the permission service isn't wired.
Related errors
- failed to write file: %w
- target file already exists and overwrite is not allowed: %s
- failed to rename file: %w
- session ID is required for executing shell command
- session ID is required for downloading files
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/3d6391f57c64aca4.
Report an issue: GitHub.