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

  1. Verify the server is running and reachable (curl the base URL)
  2. Check the client's base URL/port configuration
  3. Inspect the wrapped %w error for the underlying transport cause
  4. 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

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


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/7b1935108bc8eedf. Report an issue: GitHub.