{"record":{"id":"34da3b2b45e9144a","repo":"charmbracelet/crush","slug":"failed-to-get-session-status-code-d","errorCode":null,"errorMessage":"failed to get session: status code %d","messagePattern":"failed to get session: status code (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/client/proto.go","lineNumber":615,"sourceCode":"\tif rsp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"failed to get messages: status code %d\", rsp.StatusCode)\n\t}\n\tvar msgs []proto.Message\n\tif err := json.NewDecoder(rsp.Body).Decode(&msgs); err != nil && !errors.Is(err, io.EOF) {\n\t\treturn nil, fmt.Errorf(\"failed to decode messages: %w\", err)\n\t}\n\treturn msgs, nil\n}\n\n// GetSession retrieves a specific session as a proto type.\nfunc (c *Client) GetSession(ctx context.Context, id string, sessionID string) (*proto.Session, error) {\n\trsp, err := c.get(ctx, fmt.Sprintf(\"/workspaces/%s/sessions/%s\", id, sessionID), nil, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get session: %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: status code %d\", rsp.StatusCode)\n\t}\n\tvar sess proto.Session\n\tif err := json.NewDecoder(rsp.Body).Decode(&sess); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode session: %w\", err)\n\t}\n\treturn &sess, nil\n}\n\n// ListSessionHistoryFiles retrieves history files for a session as proto types.\nfunc (c *Client) ListSessionHistoryFiles(ctx context.Context, id string, sessionID string) ([]proto.File, error) {\n\trsp, err := c.get(ctx, fmt.Sprintf(\"/workspaces/%s/sessions/%s/history\", id, sessionID), nil, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get session history files: %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 history files: status code %d\", rsp.StatusCode)\n\t}","sourceCodeStart":597,"sourceCodeEnd":633,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/client/proto.go#L597-L633","documentation":"Thrown by Client.GetSession when the server returned a non-200 status for GET /workspaces/{id}/sessions/{sessionID}; the body is discarded and only the status code is reported. Callers resolveSession/resolveSessionByID use this to find a session, so a 404 here usually means the session id does not exist in that workspace.","triggerScenarios":"Calling GetSession with a sessionID typed wrong or already deleted (404), a workspace id that does not match (404), expired auth (401/403), or a server error while loading the session row (500).","commonSituations":"Passing a session id from a different workspace or machine; session cleaned up by retention/pruning; typos when resuming from a saved id; auth token expiry; server DB issue producing 500.","solutions":["Check the status in the error: 404 → list available sessions and confirm the id exists in this workspace.","Verify the workspace id matches the session's origin.","Re-authenticate if the status is 401/403.","Retry and check server logs for 5xx responses."],"exampleFix":"// before\nsess, err := client.GetSession(ctx, wsID, sessionID)\nif err != nil {\n    return err\n}\n// after: handle 404 as a normal \"not found\" outcome\nsess, err := client.GetSession(ctx, wsID, sessionID)\nif err != nil {\n    if strings.Contains(err.Error(), \"status code 404\") {\n        return nil, ErrSessionNotFound\n    }\n    return nil, err\n}","handlingStrategy":"fallback","validationCode":"// Resolve against the session list before fetching a specific session\nsessions, err := client.ListSessions(ctx, wsID)\nif err != nil {\n    return err\n}\nfor _, s := range sessions {\n    if s.ID == sessionID {\n        return nil // safe to call GetSession\n    }\n}\nreturn ErrSessionNotFound","typeGuard":"func isNotFound(err error) bool {\n    return strings.Contains(err.Error(), \"status code 404\")\n}","tryCatchPattern":"sess, err := client.GetSession(ctx, wsID, sessionID)\nif err != nil {\n    if isNotFound(err) {\n        // fall back to listing sessions and picking the latest\n        return latestSession(ctx, wsID)\n    }\n    return nil, err\n}","preventionTips":["Treat 404 as expected control flow: fall back to a session list instead of crashing","Persist the workspace id alongside session ids so resumes hit the right workspace","Guard against stale ids after retention/pruning deletes old sessions","Distinguish 404 (not found) from 401/403 (re-auth) and 5xx (retry) in error handling"],"tags":["http","status-code","session","not-found"],"backgroundTag":"unexpected-http-status","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}