charmbracelet/crush · error
failed to delete workspace: status code
Error message
failed to delete workspace: status code %d
What it means
DeleteWorkspace requires an exact HTTP 200; any other status (e.g. 403, 404, 409, 500) produces this error with the status code embedded. Unlike checkStatus-based paths this branch reports only the numeric code, so the server's error detail body is not included. It means the server actively rejected or failed the delete.
Solutions
- Treat 404 as success (workspace already gone) and ignore it.
- Re-list workspaces (ListWorkspaces) to refresh ids before deleting.
- If ownership errors occur, create the workspace with the current client (CreateWorkspace stamps ws.ClientID) or restart from a fresh list.
- Check server logs for the status code to find the 5xx cause.
Example fix
// before
if err := client.DeleteWorkspace(ctx, id); err != nil { return err }
// after: tolerate already-deleted
if err := client.DeleteWorkspace(ctx, id); err != nil {
if strings.Contains(err.Error(), "status code 404") {
return nil
}
return err
} Defensive patterns
Strategy: validation
Validate before calling
// verify existence and ownership before deleting
wss, err := client.ListWorkspaces(ctx)
if err != nil { return err }
owned := false
for _, w := range wss {
if w.ID == id && w.ClientID == myClientID { owned = true }
}
if !owned { return fmt.Errorf("workspace %q not owned by this client", id) } Try / catch
err := client.DeleteWorkspace(ctx, id)
var statusErr interface{ StatusCode() int }
switch {
case err == nil:
return nil
case strings.Contains(err.Error(), "status code 404"):
return nil // already gone
default:
return err
} Prevention
- Refresh the workspace list before deleting.
- Remember client IDs are process-scoped and change on restart.
- Treat 404 as success in cleanup paths.
- Match on the embedded status code, not the generic message.
When it happens
Trigger: Calling client.DeleteWorkspace(ctx, id) when the workspace does not exist (404), the client_id does not own the workspace (403/409), or the server errors while removing state (5xx).
Common situations: Deleting an already-deleted workspace from another client session; ownership mismatch because the client was restarted and minted a new client ID (NewClient generates a process-scoped ID); stale workspace list from before a server restart.
Related errors
- failed to answer question batch: status code
- failed to cancel question batch: status code
- failed to check project init: status code
- failed to decode workspace
- failed to delete workspace
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/cde074c65014eeef.
Report an issue: GitHub.
Appendix: source
Thrown at internal/client/proto.go:84
return nil, fmt.Errorf("failed to get workspace: %w", err)
}
var ws proto.Workspace
if err := json.NewDecoder(rsp.Body).Decode(&ws); err != nil {
return nil, fmt.Errorf("failed to decode workspace: %w", err)
}
return &ws, nil
}
// DeleteWorkspace deletes a workspace on the server.
func (c *Client) DeleteWorkspace(ctx context.Context, id string) error {
q := url.Values{"client_id": []string{c.clientID}}
rsp, err := c.delete(ctx, fmt.Sprintf("/workspaces/%s", id), q, nil)
if err != nil {
return fmt.Errorf("failed to delete workspace: %w", err)
}
defer rsp.Body.Close()
if rsp.StatusCode != http.StatusOK {
return fmt.Errorf("failed to delete workspace: status code %d", rsp.StatusCode)
}
return nil
}
// SetCurrentSession reports the client's current-session selection
// for the named workspace. An empty sessionID clears the entry. The
// request carries the process-scoped client ID minted in [NewClient]
// as a query parameter so the server can route the update to the
// correct [clientState] entry.
func (c *Client) SetCurrentSession(ctx context.Context, workspaceID, sessionID string) error {
q := url.Values{"client_id": []string{c.clientID}}
rsp, err := c.post(
ctx,
fmt.Sprintf("/workspaces/%s/current-session", workspaceID),
q,
jsonBody(proto.CurrentSession{SessionID: sessionID}),
http.Header{"Content-Type": []string{"application/json"}},
)View on GitHub (pinned to 7944b8e522)