{"record":{"id":"aa42f9ff590cbc67","repo":"charmbracelet/crush","slug":"timeout-waiting-for-agent-w","errorCode":null,"errorMessage":"timeout waiting for agent: %w","messagePattern":"timeout waiting for agent: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cmd/run.go","lineNumber":469,"sourceCode":"\t\tstop()\n\t\treturn true, fmt.Errorf(\"agent error: %w\", e.Payload.Error)\n\t}\n\treturn false, nil\n}\n\n// waitForAgent polls GetAgentInfo until the agent is ready, with a\n// timeout.\nfunc waitForAgent(ctx context.Context, c *client.Client, wsID string) error {\n\ttimeout := time.After(30 * time.Second)\n\tfor {\n\t\tinfo, err := c.GetAgentInfo(ctx, wsID)\n\t\tif err == nil && info.IsReady {\n\t\t\treturn nil\n\t\t}\n\t\tselect {\n\t\tcase <-timeout:\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"timeout waiting for agent: %w\", err)\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"timeout waiting for agent readiness\")\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase <-time.After(200 * time.Millisecond):\n\t\t}\n\t}\n}\n\n// overrideModels resolves model strings and updates the workspace\n// configuration via the server.\nfunc overrideModels(\n\tctx context.Context,\n\tc *client.Client,\n\tws *proto.Workspace,\n\tlargeModel, smallModel string,\n) error {\n\tcfg, err := c.GetConfig(ctx, ws.ID)","sourceCodeStart":451,"sourceCodeEnd":487,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/cmd/run.go#L451-L487","documentation":"This error is wrapped by waitForAgent (internal/cmd/run.go:459) when the 30-second readiness timeout fires while the last GetAgentInfo call itself returned an error. It means the agent never reported IsReady within the deadline AND polling kept failing, so the wrapped error is the last polling failure (connection refused, HTTP error, etc.).","triggerScenarios":"The client.Run non-interactive path calls runNonInteractive -> waitForAgent; GetAgentInfo(ctx, wsID) returns an error on every poll (server unreachable, auth failure, workspace ID invalid) for the full 30s timeout window.","commonSituations":"Server not yet started or crashed during startup; wrong server URL/port in environment; expired or missing API credentials; pointing at a workspace that was deleted; slow machine/container startup exceeding 30s.","solutions":["Inspect the wrapped cause (%w) to see why GetAgentInfo fails (connection refused vs 401 vs 404) and fix that root issue","Verify the server is running and reachable at the configured address before invoking crush run","Check credentials/environment variables used by the client","Increase the timeout or retry the run if startup is genuinely slow (resource-constrained environments)","Confirm the workspace ID is valid"],"exampleFix":"// before\nif err := runNonInteractive(...); err != nil {\n\tfmt.Println(err)\n}\n// after\nif err := runNonInteractive(...); err != nil {\n\tvar to *timeoutErr\n\tif errors.As(err, &to) {\n\t\tfmt.Printf(\"agent startup failed: %v\\n\", errors.Unwrap(err))\n\t}\n}","handlingStrategy":"retry","validationCode":"// Before invoking the run, check the server is reachable\nconn, err := net.DialTimeout(\"tcp\", serverAddr, 2*time.Second)\nif err != nil {\n\treturn fmt.Errorf(\"server unreachable at %s: %w\", serverAddr, err)\n}\nconn.Close()","typeGuard":null,"tryCatchPattern":"if err := runNonInteractive(...); err != nil {\n\tif strings.Contains(err.Error(), \"timeout waiting for agent\") {\n\t\t// log errors.Unwrap(err) for the last polling failure, then retry\n\t}\n}","preventionTips":["Health-check the server endpoint before starting non-interactive runs","Validate auth credentials and workspace ID early in scripts","Use generous timeouts in CI/containers where startup is slow","Monitor the wrapped cause (%w) — it names the real failure"],"tags":["timeout","network","startup","go"],"backgroundTag":"agent-startup-timeout","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}