charmbracelet/crush · error
failed to set provider API key: %w
Error message
failed to set provider API key: %w
What it means
After locally validating the key, SetProviderAPIKey posts to /workspaces/{id}/config/provider-key. If the HTTP request itself fails (connection refused, timeout, DNS error, context canceled), the error is wrapped with this message.
Source
Thrown at internal/client/config.go:118
}
kind = proto.APIKeyKindOAuth
b, err := json.Marshal(v)
if err != nil {
return fmt.Errorf("failed to marshal oauth token: %w", err)
}
raw = b
default:
return fmt.Errorf("unsupported api key type %T", apiKey)
}
rsp, err := c.post(ctx, fmt.Sprintf("/workspaces/%s/config/provider-key", id), nil, jsonBody(proto.ConfigProviderKeyRequest{
Scope: scope,
ProviderID: providerID,
Kind: kind,
APIKey: raw,
}), http.Header{"Content-Type": []string{"application/json"}})
if err != nil {
return fmt.Errorf("failed to set provider API key: %w", err)
}
defer rsp.Body.Close()
if rsp.StatusCode != http.StatusOK {
return fmt.Errorf("failed to set provider API key: status code %d", rsp.StatusCode)
}
return nil
}
// ImportCopilot attempts to import a GitHub Copilot token on the
// server.
func (c *Client) ImportCopilot(ctx context.Context, id string) (*oauth.Token, bool, error) {
rsp, err := c.post(ctx, fmt.Sprintf("/workspaces/%s/config/import-copilot", id), nil, nil, nil)
if err != nil {
return nil, false, fmt.Errorf("failed to import copilot: %w", err)
}
defer rsp.Body.Close()
if rsp.StatusCode != http.StatusOK {
return nil, false, fmt.Errorf("failed to import copilot: status code %d", rsp.StatusCode)View on GitHub (pinned to 7944b8e522)
Solutions
- Verify the server is running and reachable (curl the base URL)
- Check the client's base URL/port configuration
- Inspect the wrapped %w error for the underlying transport cause
- Retry with a longer context deadline if timing out
Example fix
// before
ctx := context.Background()
client.SetProviderAPIKey(ctx, wsID, scope, providerID, key)
// after
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := client.SetProviderAPIKey(ctx, wsID, scope, providerID, key); err != nil {
return fmt.Errorf("set provider key: %w", err)
} Defensive patterns
Strategy: retry
Validate before calling
// verify server reachability before calling
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, baseURL+"/health", nil)
if _, err := http.DefaultClient.Do(req); err != nil {
return fmt.Errorf("server unreachable: %w", err)
} Try / catch
err := c.SetProviderAPIKey(ctx, wsID, scope, pid, key)
for i := 0; i < 3 && err != nil; i++ {
if !isTransient(err) { break }
time.Sleep(backoff(i))
err = c.SetProviderAPIKey(ctx, wsID, scope, pid, key)
} Prevention
- Use a context with a sane timeout for all client calls
- Confirm the server URL and port in client configuration
- Retry only on transient transport errors, not on 4xx responses
When it happens
Trigger: Calling SetProviderAPIKey when the server is unreachable: connection refused, TLS failure, DNS resolution failure, or the ctx deadline expires mid-request.
Common situations: Dev server not running, wrong base URL/port in client config, VPN/proxy blocking the host, request context canceled by the user or a timeout.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- server health check failed: %s
- failed to list workspaces: %w
- failed to create workspace: %w
- failed to get MCP auth URL: %w
- failed to get session history files: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/7b1935108bc8eedf.
Report an issue: GitHub.