charmbracelet/crush · error
permission request failed: %w
Error message
permission request failed: %w
What it means
This error is returned when the tool's permission request to the configured permission service fails (the Request call itself returned an error, e.g. transport/handler failure), distinct from a denial which returns NewPermissionDeniedResponse(). The wrapped error indicates the permission workflow could not complete, so the file replacement is aborted before any write.
Source
Thrown at internal/agent/tools/lsp_replace_symbol.go:147
}
newContent := strings.Join(newLines, "\n")
sessionID := GetSessionFromContext(ctx)
if sessionID != "" && permissions != nil {
granted, err := permissions.Request(ctx, permission.CreatePermissionRequest{
SessionID: sessionID,
Path: params.FilePath,
ToolName: ReplaceSymbolToolName,
Description: fmt.Sprintf("%s symbol '%s' in %s", action, params.Symbol, params.FilePath),
Params: ReplaceSymbolPermissionsParams{
FilePath: params.FilePath,
OldContent: string(content),
NewContent: newContent,
},
})
if err != nil {
return fantasy.ToolResponse{}, fmt.Errorf("permission request failed: %w", err)
}
if !granted {
return NewPermissionDeniedResponse(), nil
}
}
if files != nil && sessionID != "" {
if _, err := files.CreateVersion(ctx, sessionID, params.FilePath, string(content)); err != nil {
slog.Warn("Failed to create file version before replace", "path", params.FilePath, "error", err)
}
}
if err := os.WriteFile(params.FilePath, []byte(newContent), 0o644); err != nil {
return fantasy.ToolResponse{}, fmt.Errorf("failed to write file: %w", err)
}
if filetracker != nil && sessionID != "" {
filetracker.RecordRead(ctx, sessionID, params.FilePath)View on GitHub (pinned to 7944b8e522)
Solutions
- Inspect the wrapped error to identify the permission provider failure.
- Attach a working permission handler/approver for the session (interactive UI or configured auto-allow rules).
- Add an allow-list entry for the edit permission in crush config so no interactive request is needed.
- Retry the operation once a permission handler is available.
Example fix
// before
// no config; every edit triggers a permission request that fails headless
// after
// crushrc
permissions {
allow ["edit"]
} Defensive patterns
Strategy: try-catch
Validate before calling
// ensure a permission handler exists before running the tool
if perms == nil || !perms.HasHandler() {
return errors.New("no permission handler attached for this session")
} Try / catch
resp, err := tool.Run(ctx, call)
if err != nil && strings.Contains(err.Error(), "permission request failed") {
// fall back to auto-allowed config or surface to user
return handlePermissionFailure(err)
} Prevention
- Configure allow-list permissions in crushrc for trusted edit operations.
- Run interactively (with UI approver attached) for permission-gated tools.
- Don't cancel sessions while permission prompts are pending.
- Test permission flows in the same environment where the tool will run.
When it happens
Trigger: Calling lsp_replace_symbol on a file requiring approval when the permissions.Request call errors: permission provider misconfigured, the UI/handler session is unavailable or closed, or the permission service's underlying request channel fails.
Common situations: Running headless where no permission approver is attached; the session was cancelled while the prompt was pending; a custom permission provider returned an error; permission timeouts in non-interactive environments.
Related errors
- session ID is required for executing shell command
- session ID is required for accessing files outside working d
- error checking file: %w
- error creating directory: %w
- error writing file: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/ed35d6b6a5c8f8e4.
Report an issue: GitHub.