{"record":{"id":"ddf7f98edc55ee80","repo":"charmbracelet/crush","slug":"failed-to-get-mcp-pending-auth-w","errorCode":null,"errorMessage":"failed to get MCP pending auth: %w","messagePattern":"failed to get MCP pending auth: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/client/proto.go","lineNumber":336,"sourceCode":"\t\treturn nil, fmt.Errorf(\"failed to get MCP states: %w\", err)\n\t}\n\tdefer rsp.Body.Close()\n\tif rsp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"failed to get MCP states: status code %d\", rsp.StatusCode)\n\t}\n\tvar states map[string]proto.MCPClientInfo\n\tif err := json.NewDecoder(rsp.Body).Decode(&states); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode MCP states: %w\", err)\n\t}\n\treturn states, nil\n}\n\n// MCPPendingAuth retrieves the MCP servers awaiting OAuth authentication\n// for a workspace.\nfunc (c *Client) MCPPendingAuth(ctx context.Context, id string) ([]proto.MCPPendingAuthServer, error) {\n\trsp, err := c.get(ctx, fmt.Sprintf(\"/workspaces/%s/mcp/pending-auth\", id), nil, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get MCP pending auth: %w\", err)\n\t}\n\tdefer rsp.Body.Close()\n\tif rsp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"failed to get MCP pending auth: status code %d\", rsp.StatusCode)\n\t}\n\tvar pending []proto.MCPPendingAuthServer\n\tif err := json.NewDecoder(rsp.Body).Decode(&pending); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode MCP pending auth: %w\", err)\n\t}\n\treturn pending, nil\n}\n\n// MCPAuthURL retrieves the current OAuth authorization URL for a named MCP\n// server, if a flow is in progress.\nfunc (c *Client) MCPAuthURL(ctx context.Context, id, name string) (string, error) {\n\tq := url.Values{\"name\": []string{name}}\n\trsp, err := c.get(ctx, fmt.Sprintf(\"/workspaces/%s/mcp/auth-url\", id), q, nil)\n\tif err != nil {","sourceCodeStart":318,"sourceCodeEnd":354,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/client/proto.go#L318-L354","documentation":"MCPPendingAuth issues GET /workspaces/{id}/mcp/pending-auth to list MCP servers awaiting OAuth, and wraps any transport failure from c.get with this message. The request produced no HTTP response; the cause (connection refused, DNS, cancelation) is in the wrapped error.","triggerScenarios":"Calling MCPPendingAuth(ctx, id) when the server is down or unreachable, the endpoint address is wrong, the connection drops, or ctx expires before the response arrives.","commonSituations":"Polling for pending OAuth servers after the daemon exited; DNS misconfiguration for a remote crush server; laptop resume killing keep-alive connections; short-lived context canceled by an outer timeout.","solutions":["Check the wrapped cause and restore connectivity (start/restart the crush server, fix the base URL).","Confirm the server is listening and the workspace id is valid.","Use context.WithTimeout with a reasonable budget and retry transient network errors with backoff.","If polling, back off after repeated transport failures instead of hot-looping."],"exampleFix":"// before\npending, err := client.MCPPendingAuth(ctx, wsID)\nif err != nil { return err }\n// after\nctx, cancel := context.WithTimeout(ctx, 10*time.Second)\ndefer cancel()\npending, err := client.MCPPendingAuth(ctx, wsID)\nif err != nil {\n    if isNetError(err) { return retryWithBackoff(...); }\n    return err\n}","handlingStrategy":"try-catch","validationCode":"if err := ctx.Err(); err != nil { return fmt.Errorf(\"context already done before MCPPendingAuth: %w\", err) }\nif wsID == \"\" { return errors.New(\"workspace id required\") }","typeGuard":"func isContextErr(err error) bool {\n\treturn errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded)\n}","tryCatchPattern":"pending, err := client.MCPPendingAuth(ctx, wsID)\nif err != nil {\n\tif isContextErr(err) {\n\t\treturn nil, fmt.Errorf(\"pending-auth poll canceled: %w\", err) // caller may reschedule\n\t}\n\treturn nil, fmt.Errorf(\"pending-auth unreachable: %w\", err)\n}","preventionTips":["Give OAuth polling its own context with a generous timeout so outer cancelation doesn't kill it.","Check ctx.Err() before issuing the call.","Back off between polls; don't hot-loop a dead server.","Validate wsID and server reachability before starting the OAuth flow."],"tags":["network","http-client","mcp","oauth","go"],"backgroundTag":"http-request-failed","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}