{"record":{"id":"802bab7b4d52be23","repo":"charmbracelet/crush","slug":"failed-to-disable-docker-mcp-status-code-d","errorCode":null,"errorMessage":"failed to disable docker MCP: status code %d","messagePattern":"failed to disable docker MCP: status code (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/client/config.go","lineNumber":284,"sourceCode":"\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 {\n\t\treturn fmt.Errorf(\"failed to refresh MCP tools: status code %d\", rsp.StatusCode)\n\t}\n\treturn nil\n}","sourceCodeStart":266,"sourceCodeEnd":302,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/client/config.go#L266-L302","documentation":"Returned by Client.DisableDockerMCP when the POST succeeded at the transport level but the server responded with a non-200 status. Only 200 is accepted as success. Typical codes: 404 for a missing workspace or route, 401/403 for auth, 500 if the server errors while disabling the Docker MCP integration (e.g. MCP server already removed).","triggerScenarios":"Calling DisableDockerMCP on a nonexistent or already-deleted workspace (404), with insufficient permissions (403), against a server that predates the docker MCP endpoints (404/405), or when the server-side disable handler fails (500).","commonSituations":"Double-disable from concurrent cleanup logic hitting a removed MCP entry; server upgrade removed the route; expired credentials; workspace suspended so MCP mutation is rejected.","solutions":["Parse the status code from the message and branch: 404 may safely mean 'already disabled' — treat idempotently.","For 401/403, refresh credentials and retry.","For 500, inspect server logs for the docker MCP disable handler error.","Ensure the workspace ID is valid and the server supports the disable route.","Guard against concurrent duplicate disable calls for the same workspace."],"exampleFix":"// before\nerr := client.DisableDockerMCP(ctx, wsID) // status code 404\nif err != nil { return err }\n// after\nerr := client.DisableDockerMCP(ctx, wsID)\nif err != nil && strings.Contains(err.Error(), \"status code 404\") {\n    return nil // already disabled / workspace gone: treat as idempotent success\n}\nif err != nil { return err }","handlingStrategy":"fallback","validationCode":null,"typeGuard":"func isNon200(err error) (code int, ok bool) {\n    m := regexp.MustCompile(`status code (\\d+)`).FindStringSubmatch(err.Error())\n    if len(m) < 2 { return 0, false }\n    code, err2 := strconv.Atoi(m[1])\n    return code, err2 == nil\n}","tryCatchPattern":"err := client.DisableDockerMCP(ctx, wsID)\nif err != nil {\n    if code, ok := isNon200(err); ok && code == 404 {\n        // already disabled or workspace gone — treat as success (idempotent teardown)\n        return nil\n    }\n    return err\n}","preventionTips":["Treat disable as idempotent: 404 usually means already disabled.","Serialize teardown so concurrent workers don't double-disable.","Refresh credentials on 401/403 before retrying.","Verify the server supports the docker MCP disable route."],"tags":["http-client","http-status","mcp","docker","api-error"],"backgroundTag":"http-non-200-response","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}