charmbracelet/crush · error
failed to list workspaces: %w
Error message
failed to list workspaces: %w
What it means
ListWorkspaces calls GET /workspaces; this error wraps any transport-level failure from the HTTP client (connection refused, timeout, canceled context) before a response is obtained. It is a request-sending failure, not a server-reported status.
Source
Thrown at internal/client/proto.go:27
"fmt"
"io"
"log/slog"
"net/http"
"net/url"
"time"
"github.com/charmbracelet/crush/internal/config"
"github.com/charmbracelet/crush/internal/message"
"github.com/charmbracelet/crush/internal/proto"
"github.com/charmbracelet/crush/internal/pubsub"
"github.com/charmbracelet/x/powernap/pkg/lsp/protocol"
)
// ListWorkspaces retrieves all workspaces from the server.
func (c *Client) ListWorkspaces(ctx context.Context) ([]proto.Workspace, error) {
rsp, err := c.get(ctx, "/workspaces", nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to list workspaces: %w", err)
}
defer rsp.Body.Close()
if rsp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to list workspaces: status code %d", rsp.StatusCode)
}
var workspaces []proto.Workspace
if err := json.NewDecoder(rsp.Body).Decode(&workspaces); err != nil {
return nil, fmt.Errorf("failed to decode workspaces: %w", err)
}
return workspaces, nil
}
// CreateWorkspace creates a new workspace on the server.
func (c *Client) CreateWorkspace(ctx context.Context, ws proto.Workspace) (*proto.Workspace, error) {
ws.ClientID = c.clientID
rsp, err := c.post(ctx, "/workspaces", nil, jsonBody(ws), http.Header{"Content-Type": []string{"application/json"}})
if err != nil {
return nil, fmt.Errorf("failed to create workspace: %w", err)View on GitHub (pinned to 7944b8e522)
Solutions
- Check the wrapped error: connection refused means the daemon is not running — start it.
- Verify the server address/port configured for the client.
- Check for context cancellation/deadline and increase the timeout if the server is slow to start.
- Ensure no firewall or proxy blocks the connection to the daemon.
Example fix
// before
workspaces, err := client.ListWorkspaces(ctx)
if err != nil {
return err
}
// after
workspaces, err := client.ListWorkspaces(ctx)
if err != nil {
if isConnectionRefused(err) {
if startErr := startServer(ctx); startErr != nil {
return startErr
}
workspaces, err = client.ListWorkspaces(ctx)
}
if err != nil {
return err
}
} Defensive patterns
Strategy: retry
Validate before calling
// Verify the daemon is listening before calling
conn, err := net.DialTimeout("tcp", serverAddr, 2*time.Second)
if err != nil {
return fmt.Errorf("daemon not reachable at %s: %w", serverAddr, err)
}
conn.Close() Type guard
func isTransportError(err error) bool {
// Wrapped transport failure: no "status code" component means the request never completed
s := err.Error()
return !strings.Contains(s, "status code")
} Try / catch
workspaces, err := client.ListWorkspaces(ctx)
if err != nil {
var netErr net.Error
if errors.As(err, &netErr) || strings.Contains(err.Error(), "connection refused") {
if startErr := startDaemon(ctx); startErr == nil {
workspaces, err = client.ListWorkspaces(ctx)
}
}
if err != nil {
return err
}
} Prevention
- Start/verify the daemon before client initialization.
- Use a generous context timeout during startup to absorb slow server boot.
- Confirm the configured address/port matches the running daemon.
- Retry transport errors with exponential backoff before failing.
When it happens
Trigger: Calling ListWorkspaces when the daemon is not running or unreachable, the context is canceled, the connection is refused/reset, or DNS/TCP fails for the configured server address.
Common situations: The background server died or was never started; wrong port/address in configuration; firewall blocking localhost port; context deadline exceeded under slow startup; shutdownLegacyStaleServer probing a server that already exited.
Related errors
- server health check failed: %s
- failed to set provider API key: %w
- failed to create workspace: %w
- failed to get MCP auth URL: %w
- failed to get session history files: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/3a070d7f5f71dbac.
Report an issue: GitHub.