{"record":{"id":"fca23244f82a389b","repo":"charmbracelet/crush","slug":"failed-to-get-workspace-w","errorCode":null,"errorMessage":"failed to get workspace: %w","messagePattern":"failed to get workspace: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/client/proto.go","lineNumber":62,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create workspace: %w\", err)\n\t}\n\tdefer rsp.Body.Close()\n\tif err := checkStatus(rsp); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create workspace: %w\", err)\n\t}\n\tvar created proto.Workspace\n\tif err := json.NewDecoder(rsp.Body).Decode(&created); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode workspace: %w\", err)\n\t}\n\treturn &created, nil\n}\n\n// GetWorkspace retrieves a workspace from the server.\nfunc (c *Client) GetWorkspace(ctx context.Context, id string) (*proto.Workspace, error) {\n\trsp, err := c.get(ctx, fmt.Sprintf(\"/workspaces/%s\", id), nil, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get workspace: %w\", err)\n\t}\n\tdefer rsp.Body.Close()\n\tif err := checkStatus(rsp); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get workspace: %w\", err)\n\t}\n\tvar ws proto.Workspace\n\tif err := json.NewDecoder(rsp.Body).Decode(&ws); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode workspace: %w\", err)\n\t}\n\treturn &ws, nil\n}\n\n// DeleteWorkspace deletes a workspace on the server.\nfunc (c *Client) DeleteWorkspace(ctx context.Context, id string) error {\n\tq := url.Values{\"client_id\": []string{c.clientID}}\n\trsp, err := c.delete(ctx, fmt.Sprintf(\"/workspaces/%s\", id), q, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to delete workspace: %w\", err)","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/client/proto.go#L44-L80","documentation":"GetWorkspace wraps an error returned by the client's underlying c.get transport call (building/sending the HTTP GET /workspaces/{id}). This fires before any status checking, so it indicates the request itself failed at the network/transport layer, not that the server rejected it. The original error (e.g. connection refused, context canceled) is preserved via %w.","triggerScenarios":"Calling client.GetWorkspace(ctx, id) when the crush server is unreachable: wrong URL/port, server process down, TLS handshake failure, or the passed context is canceled/expired mid-request.","commonSituations":"crush serve not running or crashed; client configured with a stale or mistyped server address; firewall/network partition; a long-running operation whose context deadline exceeded before the GET completed.","solutions":["Confirm the crush server is running and reachable (curl the /workspaces endpoint).","Check the client's configured server URL/port matches the server's actual listen address.","Use errors.Is(err, context.DeadlineExceeded) to distinguish timeout vs connectivity and retry with a longer deadline.","Retry the request; transient network errors often resolve.","Verify DNS resolution and any proxy environment variables (HTTP_PROXY/HTTPS_PROXY) are correct."],"exampleFix":"// before\nws, err := client.GetWorkspace(ctx, id)\nif err != nil { return err }\n// after: classify and retry transport errors\nws, err := client.GetWorkspace(ctx, id)\nif err != nil {\n    if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) {\n        return err\n    }\n    time.Sleep(time.Second)\n    ws, err = client.GetWorkspace(ctx, id)\n    if err != nil { return fmt.Errorf(\"get workspace: %w\", err) }\n}","handlingStrategy":"retry","validationCode":"// probe reachability before the call\nconn, err := net.DialTimeout(\"tcp\", host, 2*time.Second)\nif err != nil { return fmt.Errorf(\"server unreachable: %w\", err) }\nconn.Close()","typeGuard":null,"tryCatchPattern":"ws, err := client.GetWorkspace(ctx, id)\nif err != nil {\n    if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {\n        return err\n    }\n    var ne net.Error\n    if errors.As(err, &ne) && ne.Timeout() {\n        return retryWithBackoff()\n    }\n    return err\n}","preventionTips":["Health-check the server before workspace operations.","Use generous but bounded context deadlines.","Centralize retry/backoff for all client calls.","Keep server address in one validated config value."],"tags":["network","http-client","workspace"],"backgroundTag":"connection-refused","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}