{"record":{"id":"2069cb5f7ae75140","repo":"charmbracelet/crush","slug":"failed-to-get-session-agent-info-status-code-d","errorCode":null,"errorMessage":"failed to get session agent info: status code %d","messagePattern":"failed to get session agent info: status code (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/client/proto.go","lineNumber":554,"sourceCode":"\tif rsp.StatusCode != http.StatusOK {\n\t\treturn proto.ShellCommandResponse{}, fmt.Errorf(\"failed to run shell command: status code %d\", rsp.StatusCode)\n\t}\n\tvar resp proto.ShellCommandResponse\n\tif err := json.NewDecoder(rsp.Body).Decode(&resp); err != nil {\n\t\treturn proto.ShellCommandResponse{}, fmt.Errorf(\"failed to decode shell command response: %w\", err)\n\t}\n\treturn resp, nil\n}\n\n// GetAgentSessionInfo retrieves the agent session info for a workspace.\nfunc (c *Client) GetAgentSessionInfo(ctx context.Context, id string, sessionID string) (*proto.AgentSession, error) {\n\trsp, err := c.get(ctx, fmt.Sprintf(\"/workspaces/%s/agent/sessions/%s\", id, sessionID), nil, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get session agent info: %w\", err)\n\t}\n\tdefer rsp.Body.Close()\n\tif rsp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"failed to get session agent info: status code %d\", rsp.StatusCode)\n\t}\n\tvar info proto.AgentSession\n\tif err := json.NewDecoder(rsp.Body).Decode(&info); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode session agent info: %w\", err)\n\t}\n\treturn &info, nil\n}\n\n// AgentSummarizeSession requests a session summarization.\nfunc (c *Client) AgentSummarizeSession(ctx context.Context, id string, sessionID string) error {\n\trsp, err := c.post(ctx, fmt.Sprintf(\"/workspaces/%s/agent/sessions/%s/summarize\", id, sessionID), nil, nil, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to summarize session: %w\", err)\n\t}\n\tdefer rsp.Body.Close()\n\tif rsp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"failed to summarize session: status code %d\", rsp.StatusCode)\n\t}","sourceCodeStart":536,"sourceCodeEnd":572,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/client/proto.go#L536-L572","documentation":"GetAgentSessionInfo expects 200 OK. Any other status yields this error with the numeric status code, without decoding the body. Typically 404 when the session does not exist or has ended, 401/403 for auth problems, or 5xx for server faults.","triggerScenarios":"Polling session status after the session was closed or expired (404); expired auth token (401/403); server error while assembling AgentSession info (5xx).","commonSituations":"AgentIsSessionBusy treating a dead session as an error instead of 'not busy'; long-lived clients whose tokens expired; races where the session is deleted between acquiring the id and polling.","solutions":["For 404, treat the session as terminated — re-create the session rather than retrying.","For 401/403, refresh credentials and retry once.","For 5xx, retry with backoff and check server health.","Verify workspace/session IDs are current; stale IDs from a previous server instance are a frequent cause."],"exampleFix":"// before\ninfo, err := client.GetAgentSessionInfo(ctx, wsID, sid)\nif err != nil { return false, err }\n// after\ninfo, err := client.GetAgentSessionInfo(ctx, wsID, sid)\nif err != nil {\n    if strings.Contains(err.Error(), \"status code 404\") {\n        return false, nil // session gone -> not busy\n    }\n    return false, err\n}","handlingStrategy":"fallback","validationCode":"// Go: confirm the session was recently seen before interpreting 404 as terminal\nlastSeen, seen := sessionCache[sid]\nif seen && time.Since(lastSeen) < time.Minute {\n    // stale-404 unlikely; treat other statuses first\n}","typeGuard":"// Go: branch on 404 vs other statuses\nfunc isNotFound(err error) bool {\n    return strings.Contains(err.Error(), \"status code 404\")\n}","tryCatchPattern":"info, err := client.GetAgentSessionInfo(ctx, wsID, sid)\nif err != nil {\n    if isNotFound(err) {\n        return nil, nil // session ended -> caller treats as 'not busy'\n    }\n    if strings.Contains(err.Error(), \"status code 401\") {\n        return refreshAuthAndFetch()\n    }\n    return nil, err\n}","preventionTips":["Map 404 to 'session gone' semantics in busy-check helpers instead of failing.","Refresh tokens proactively in long-lived clients to avoid 401 noise.","For 5xx, retry with backoff; for 4xx, fix the request or IDs.","Cache session IDs only briefly — they become stale after server restarts."],"tags":["http-status","session-info"],"backgroundTag":"unexpected-http-status","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}