{"record":{"id":"7b1935108bc8eedf","repo":"charmbracelet/crush","slug":"failed-to-set-provider-api-key-w","errorCode":null,"errorMessage":"failed to set provider API key: %w","messagePattern":"failed to set provider API key: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/client/config.go","lineNumber":118,"sourceCode":"\t\t}\n\t\tkind = proto.APIKeyKindOAuth\n\t\tb, err := json.Marshal(v)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to marshal oauth token: %w\", err)\n\t\t}\n\t\traw = b\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported api key type %T\", apiKey)\n\t}\n\n\trsp, err := c.post(ctx, fmt.Sprintf(\"/workspaces/%s/config/provider-key\", id), nil, jsonBody(proto.ConfigProviderKeyRequest{\n\t\tScope:      scope,\n\t\tProviderID: providerID,\n\t\tKind:       kind,\n\t\tAPIKey:     raw,\n\t}), http.Header{\"Content-Type\": []string{\"application/json\"}})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to set provider API key: %w\", err)\n\t}\n\tdefer rsp.Body.Close()\n\tif rsp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"failed to set provider API key: status code %d\", rsp.StatusCode)\n\t}\n\treturn nil\n}\n\n// ImportCopilot attempts to import a GitHub Copilot token on the\n// server.\nfunc (c *Client) ImportCopilot(ctx context.Context, id string) (*oauth.Token, bool, error) {\n\trsp, err := c.post(ctx, fmt.Sprintf(\"/workspaces/%s/config/import-copilot\", id), nil, nil, nil)\n\tif err != nil {\n\t\treturn nil, false, fmt.Errorf(\"failed to import copilot: %w\", err)\n\t}\n\tdefer rsp.Body.Close()\n\tif rsp.StatusCode != http.StatusOK {\n\t\treturn nil, false, fmt.Errorf(\"failed to import copilot: status code %d\", rsp.StatusCode)","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/client/config.go#L100-L136","documentation":"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.","triggerScenarios":"Calling SetProviderAPIKey when the server is unreachable: connection refused, TLS failure, DNS resolution failure, or the ctx deadline expires mid-request.","commonSituations":"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.","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"],"exampleFix":"// before\nctx := context.Background()\nclient.SetProviderAPIKey(ctx, wsID, scope, providerID, key)\n// after\nctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\ndefer cancel()\nif err := client.SetProviderAPIKey(ctx, wsID, scope, providerID, key); err != nil {\n    return fmt.Errorf(\"set provider key: %w\", err)\n}","handlingStrategy":"retry","validationCode":"// verify server reachability before calling\nreq, _ := http.NewRequestWithContext(ctx, http.MethodGet, baseURL+\"/health\", nil)\nif _, err := http.DefaultClient.Do(req); err != nil {\n    return fmt.Errorf(\"server unreachable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"err := c.SetProviderAPIKey(ctx, wsID, scope, pid, key)\nfor i := 0; i < 3 && err != nil; i++ {\n    if !isTransient(err) { break }\n    time.Sleep(backoff(i))\n    err = c.SetProviderAPIKey(ctx, wsID, scope, pid, key)\n}","preventionTips":["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"],"tags":["network","http","client"],"backgroundTag":"http-request-failed","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}