charmbracelet/crush · error

failed to create workspace: server kept shutting down

Error message

failed to create workspace: server kept shutting down

What it means

createWorkspaceOnLiveServer in internal/cmd/root.go gives up after maxStaleServerRetries attempts when every failure is client.ErrServerShuttingDown, returning the fixed message 'failed to create workspace: server kept shutting down'. It means a dying server kept being hit and even replacement attempts did not yield a healthy server.

Source

Thrown at internal/cmd/root.go:481

// 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
		}
	}
	if err := spawnAndWaitReady(cmd, hostURL); err != nil {
		return fmt.Errorf("failed to initialize crush server: %v", err)
	}
	return nil
}

// ensureServer auto-starts a detached server if the socket file does not
// exist. When the socket exists, it verifies that the running server

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Find and kill all crush server processes: pgrep -af crush; pkill -f 'crush serve'
  2. Remove the stale socket file and retry so a fresh server spawns
  3. Disable or fix the supervisor (systemd unit / docker restart policy) that keeps cycling the server
  4. Reboot or wait for system shutdown to complete before retrying

Example fix

// shell, before
crush  # keeps hitting a cycling server
// after
pkill -f 'crush serve'; rm -f ~/.local/share/crush/crush.sock
crush
Defensive patterns

Strategy: retry

Validate before calling

if running, err := serverIsRunning(sock); err == nil && !running {
    os.Remove(sock) // clear stale socket before connecting
}

Try / catch

ws, err := createWorkspaceOnLiveServer(cmd, req, replace)
if err != nil {
    if strings.Contains(err.Error(), "server kept shutting down") {
        pkill -f 'crush serve'; os.Remove(sock); // then retry from a clean state
    }
    return err
}

Prevention

When it happens

Trigger: Every CreateWorkspace call across all retries returned ErrServerShuttingDown — e.g. multiple stale servers in a shutdown loop, or a supervisor (systemd/docker) continuously restarting/terminating the server on the same socket.

Common situations: Container orchestrator repeatedly restarting the crush server; multiple crush processes racing on one unix socket; system shutdown in progress; socket file lingering while its server exits.

Related errors


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