{"record":{"id":"3f0761953480158f","repo":"charmbracelet/crush","slug":"failed-to-update-agent-w","errorCode":null,"errorMessage":"failed to update agent: %w","messagePattern":"failed to update agent: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/client/proto.go","lineNumber":477,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get agent status: %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 agent status: %w\", err)\n\t}\n\tvar info proto.AgentInfo\n\tif err := json.NewDecoder(rsp.Body).Decode(&info); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode agent status: %w\", err)\n\t}\n\treturn &info, nil\n}\n\n// UpdateAgent triggers an agent model update on the server.\nfunc (c *Client) UpdateAgent(ctx context.Context, id string) error {\n\trsp, err := c.post(ctx, fmt.Sprintf(\"/workspaces/%s/agent/update\", id), nil, nil, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to update agent: %w\", err)\n\t}\n\tdefer rsp.Body.Close()\n\tif rsp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"failed to update agent: status code %d\", rsp.StatusCode)\n\t}\n\treturn nil\n}\n\n// SendMessage sends a message to the agent for a workspace.\n//\n// When runID is non-empty it is echoed back on the resulting\n// proto.RunComplete event, giving the caller a unique correlator\n// for completion detection. Pass \"\" when the caller does not need\n// to distinguish its own turn's terminal event from any concurrent\n// turn on the same session (e.g. interactive TUI usage).\nfunc (c *Client) SendMessage(ctx context.Context, id string, sessionID, runID, prompt string, attachments ...message.Attachment) error {\n\trsp, err := c.post(ctx, fmt.Sprintf(\"/workspaces/%s/agent\", id), nil, jsonBody(proto.AgentMessage{\n\t\tSessionID:   sessionID,","sourceCodeStart":459,"sourceCodeEnd":495,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/client/proto.go#L459-L495","documentation":"UpdateAgent posts to /workspaces/{id}/agent/update to trigger a server-side agent model update. This error wraps any transport-level failure from the HTTP post itself (connection failure, timeout, request-build error, DNS failure), preserving the underlying cause via %w. It is thrown before the response status is ever inspected.","triggerScenarios":"Calling UpdateAgent when the server is unreachable, the connection is refused or reset, the request times out, or c.post fails to construct/dispatch the HTTP request (e.g. malformed URL from an empty or invalid workspace id).","commonSituations":"Server not started or listening on a different port; stale workspace id after a restart; network/VPN interruption; TLS or proxy misconfiguration; running against a base URL pointing at a non-existent host.","solutions":["Verify the server/base URL is correct and the server process is running and reachable (curl the endpoint).","Check network connectivity (DNS, proxy, firewall, VPN) from the client host.","Confirm the workspace id passed to UpdateAgent is a valid, existing id (non-empty, no whitespace).","Inspect the wrapped error (%w chain) for the concrete root cause (timeout vs refused vs TLS)."],"exampleFix":"// before: no reachability check\nerr := client.UpdateAgent(ctx, workspaceID)\n// after: fail fast with a clear cause\nif err := ctx.Err(); err != nil {\n    return fmt.Errorf(\"update agent aborted: %w\", err)\n}\nif err := client.UpdateAgent(ctx, workspaceID); err != nil {\n    return fmt.Errorf(\"update agent for %s: %w\", workspaceID, err)\n}","handlingStrategy":"try-catch","validationCode":"// Go: pre-flight check before calling UpdateAgent\nif workspaceID == \"\" {\n    return fmt.Errorf(\"workspace id is required\")\n}\nif err := ctx.Err(); err != nil {\n    return fmt.Errorf(\"context already cancelled: %w\", err)\n}","typeGuard":"// Go: unwrap and classify the transport error\nfunc isTransportError(err error) bool {\n    var ne net.Error\n    return errors.As(err, &ne) || errors.Is(err, context.DeadlineExceeded) ||\n        errors.Is(err, syscall.ECONNREFUSED)\n}","tryCatchPattern":"if err := client.UpdateAgent(ctx, id); err != nil {\n    var root error\n    errors.As(err, &root) // %w chain preserves the cause\n    log.Printf(\"update agent failed: %v (cause: %v)\", err, root)\n    return err\n}","preventionTips":["Health-check the server endpoint before batch agent updates.","Never pass empty or stale workspace IDs; re-list workspaces on failure.","Set explicit context timeouts so hangs become errors, not freezes.","Always inspect the unwrapped cause; 'failed to update agent' alone is ambiguous."],"tags":["network","http-client","rest-client","agent-update"],"backgroundTag":"http-request-failed","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}