charmbracelet/crush · error

failed to create workspace: %v

Error message

failed to create workspace: %v

What it means

createWorkspaceOnLiveServer in internal/cmd/root.go retries client.CreateWorkspace up to maxStaleServerRetries when the server reports it is shutting down (client.ErrServerShuttingDown). Any non-shutdown error, or exhausting the final retry, returns 'failed to create workspace: %v' wrapping the underlying cause.

Source

Thrown at internal/cmd/root.go:473

// createWorkspaceOnLiveServer creates the workspace, retrying against a
// replacement when the server it reached has already committed to shutting
// itself down for being idle.
//
// That race is unavoidable: the server decides to exit while no client is
// talking to it, and a client can arrive between that decision and the
// socket going away. The decision is final on the server's side, so the
// only correct response is to bring up a fresh server and ask again
// instead of failing the command.
func createWorkspaceOnLiveServer(
	ctx context.Context, c *client.Client, req proto.Workspace, replace func() error,
) (*proto.Workspace, error) {
	for attempt := range maxStaleServerRetries {
		ws, err := c.CreateWorkspace(ctx, req)
		if err == nil {
			return ws, nil
		}
		if !errors.Is(err, client.ErrServerShuttingDown) || attempt == maxStaleServerRetries-1 {
			return nil, fmt.Errorf("failed to create workspace: %v", err)
		}
		slog.Warn("Server is shutting down; retrying against a replacement",
			"attempt", attempt+1, "error", err)
		if err := replace(); err != nil {
			return nil, err
		}
	}
	return nil, fmt.Errorf("failed to create workspace: server kept shutting down")
}

// replaceExitingServer waits out the socket of a server that has committed
// to exiting, then brings up a fresh one.
func replaceExitingServer(cmd *cobra.Command, hostURL *url.URL) error {
	if hostURL.Scheme == "unix" {
		if err := awaitSocketGone(cmd.Context(), hostURL); err != nil {
			return err
		}
	}

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Re-run the command — a fresh server may start via ensureServer
  2. Check server health/logs (`crush logs`) for the underlying CreateWorkspace error
  3. Kill stale servers: pkill crush; wait for the socket to disappear, then retry
  4. If using a remote host, verify connectivity and server-side capacity/auth

Example fix

// before
c.ConnectAndUse() // hits a dying server once and fails
// after
// retry loop already built in; on failure:
// pkill -f 'crush serve' && crush  # lets ensureServer spawn a fresh server
Defensive patterns

Strategy: retry

Validate before calling

if _, err := c.HealthCheck(ctx); err != nil {
    return fmt.Errorf("server unhealthy before workspace creation: %w", err)
}

Try / catch

ws, err := c.CreateWorkspace(ctx, req)
if err != nil {
    if errors.Is(err, client.ErrServerShuttingDown) {
        // wait for replacement server, then retry
    }
    return fmt.Errorf("failed to create workspace: %w", err)
}

Prevention

When it happens

Trigger: The remote server rejects CreateWorkspace — workspace limit reached, auth failure, server-side DB error, or the server is mid-shutdown on the last allowed attempt so the error is surfaced instead of retried.

Common situations: A stale crush server process is terminating while the CLI connects; server crashed mid-request; connecting to a server owned by another user/instance that refuses the request; network drop between CLI and HTTP server.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/ec11f7803e62ab6e. Report an issue: GitHub.