{"record":{"id":"9b5b4cdb8aeb7ad9","repo":"charmbracelet/crush","slug":"failed-to-disable-docker-mcp-w-9b5b4c","errorCode":null,"errorMessage":"failed to disable docker MCP: %w","messagePattern":"failed to disable docker MCP: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/client/config.go","lineNumber":280,"sourceCode":"\n// EnableDockerMCP enables the Docker MCP server on the workspace.\nfunc (c *Client) EnableDockerMCP(ctx context.Context, id string) error {\n\trsp, err := c.post(ctx, fmt.Sprintf(\"/workspaces/%s/mcp/docker/enable\", id), nil, nil, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to enable docker MCP: %w\", err)\n\t}\n\tdefer rsp.Body.Close()\n\tif rsp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"failed to enable docker MCP: status code %d\", rsp.StatusCode)\n\t}\n\treturn nil\n}\n\n// DisableDockerMCP disables the Docker MCP server on the workspace.\nfunc (c *Client) DisableDockerMCP(ctx context.Context, id string) error {\n\trsp, err := c.post(ctx, fmt.Sprintf(\"/workspaces/%s/mcp/docker/disable\", id), nil, nil, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to disable docker MCP: %w\", err)\n\t}\n\tdefer rsp.Body.Close()\n\tif rsp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"failed to disable docker MCP: status code %d\", rsp.StatusCode)\n\t}\n\treturn nil\n}\n\n// RefreshMCPTools refreshes tools for a named MCP server.\nfunc (c *Client) RefreshMCPTools(ctx context.Context, id, name string) error {\n\trsp, err := c.post(ctx, fmt.Sprintf(\"/workspaces/%s/mcp/refresh-tools\", id), nil, jsonBody(struct {\n\t\tName string `json:\"name\"`\n\t}{Name: name}), http.Header{\"Content-Type\": []string{\"application/json\"}})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to refresh MCP tools: %w\", err)\n\t}\n\tdefer rsp.Body.Close()\n\tif rsp.StatusCode != http.StatusOK {","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/client/config.go#L262-L298","documentation":"This error is returned by Client.DisableDockerMCP when the HTTP POST to /workspaces/{id}/mcp/docker/disable fails at the transport level before a status code could be read. The root cause is wrapped with %w, so callers can distinguish timeouts, refusals, and cancellations. Like the other transport errors here, it indicates the operation never reached the server successfully.","triggerScenarios":"Calling DisableDockerMCP(ctx, workspaceID) when the connection fails, DNS lookup fails, the request times out, or the context is cancelled mid-flight.","commonSituations":"Server shut down during teardown; flaky network in CI pipelines; wrong base URL after migrating environments; short-lived context passed from a request handler that returns early.","solutions":["Verify the server is running and the base URL is correct.","Classify the wrapped cause with errors.Is/As and handle timeouts/refusals differently.","Use a context with sufficient deadline for the disable operation.","Retry with backoff for transient network errors.","Check proxy/firewall allow the POST path."],"exampleFix":"// before\nctx := r.Context() // dies with the HTTP handler\nclient.DisableDockerMCP(ctx, wsID)\n// after\nctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\ndefer cancel()\nif err := client.DisableDockerMCP(ctx, wsID); err != nil {\n    return fmt.Errorf(\"disable docker MCP failed (server reachable?): %w\", err)\n}","handlingStrategy":"retry","validationCode":"// Use an independent context so handler cancellation doesn't kill the call\nctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\ndefer cancel()\n_ = ctx // pass to DisableDockerMCP","typeGuard":"func isRetryable(err error) bool {\n    var ne net.Error\n    if errors.As(err, &ne) { return true }\n    return errors.Is(err, context.DeadlineExceeded) || errors.Is(err, syscall.ECONNREFUSED)\n}","tryCatchPattern":"err := client.DisableDockerMCP(ctx, wsID)\nfor i := 0; err != nil && isRetryable(err) && i < 3; i++ {\n    time.Sleep(time.Duration(1<<i) * time.Second)\n    err = client.DisableDockerMCP(ctx, wsID)\n}\nif err != nil { return err }","preventionTips":["Don't derive the context from a request handler that may return early.","Bound the call with a generous timeout for teardown operations.","Retry transient network errors during cleanup.","Confirm the base URL is correct per environment."],"tags":["http-client","network","mcp","docker","wrapped-error"],"backgroundTag":"http-request-transport-failure","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}