charmbracelet/crush · error · ErrClientNotAttached
client not attached
Error message
client not attached
What it means
ErrClientNotAttached reports that an operation requiring the caller's client to hold an active attachment (SSE stream claim) on a workspace was attempted without one. The backend treats the attachment as a refcount on the workspace; without it the client has no standing to issue workspace-scoped calls. Returned by SetCurrentSession and surfaced through handleError.
Source
Thrown at internal/backend/backend.go:38
"github.com/charmbracelet/crush/internal/csync"
"github.com/charmbracelet/crush/internal/db"
"github.com/charmbracelet/crush/internal/proto"
"github.com/charmbracelet/crush/internal/skills"
"github.com/charmbracelet/crush/internal/ui/util"
"github.com/charmbracelet/crush/internal/version"
"github.com/google/uuid"
)
// Common errors returned by backend operations.
var (
ErrWorkspaceNotFound = errors.New("workspace not found")
ErrLSPClientNotFound = errors.New("LSP client not found")
ErrAgentNotInitialized = errors.New("agent coordinator not initialized")
ErrPathRequired = errors.New("path is required")
ErrInvalidPermissionAction = errors.New("invalid permission action")
ErrUnknownCommand = errors.New("unknown command")
ErrInvalidClientID = errors.New("invalid client_id")
ErrClientNotAttached = errors.New("client not attached")
ErrWorkspaceClosing = errors.New("workspace closing")
ErrServerShuttingDown = errors.New("server is shutting down")
ErrServerNotIdle = errors.New("server is hosting live workspaces")
ErrClientRetired = errors.New("client has been retired")
ErrChannelOptInMismatch = errors.New("requested channels differ from the existing workspace; channels are an explicit opt-in and are not shared across duplicate creates")
)
// DefaultCreateGrace is the window in which a client must open an SSE
// stream after creating a workspace before its creation hold is
// released. Exposed as a package variable so tests can shorten it.
var DefaultCreateGrace = 30 * time.Second
// DefaultIdleShutdownDelay is how long the server stays alive after its
// last workspace is released before it shuts itself down. The delay
// exists so a client that closes one session and opens another moments
// later (the same directory or a different one) reuses the still-running
// server instead of racing its shutdown: with an immediate shutdown the
// new client can attach to — or create a workspace on — a server that isView on GitHub (pinned to 7944b8e522)
Solutions
- Attach (open the SSE stream) before issuing workspace-scoped calls
- On reconnect, re-attach to the workspace and re-issue the operation
- Verify the client did not explicitly release the workspace earlier in its lifecycle
Example fix
// before
backend.SetCurrentSession(ctx, clientID, sessionID) // never attached
// after
ws, err := backend.AttachClient(ctx, clientID, path)
if err != nil { return err }
backend.SetCurrentSession(ctx, clientID, sessionID) Defensive patterns
Strategy: type-guard
Type guard
func isErrClientNotAttached(err error) bool {
return errors.Is(err, backend.ErrClientNotAttached)
} Try / catch
err := backend.SetCurrentSession(ctx, clientID, sessionID)
switch {
case errors.Is(err, backend.ErrClientNotAttached):
if _, aerr := backend.AttachClient(ctx, clientID, path); aerr != nil {
return aerr
}
return backend.SetCurrentSession(ctx, clientID, sessionID)
case err != nil:
return err
} Prevention
- Open the SSE attachment before any workspace-scoped call
- Re-attach immediately on stream drop, inside the detach grace window
- Centralize attach state in one client object so calls cannot skip it
When it happens
Trigger: Calling SetCurrentSession (or other workspace-scoped operations) from a client that never attached, whose attachment was released, or whose SSE stream dropped and was not re-established before the detach grace elapsed.
Common situations: Reusing a workspace ID after a client restart without re-attaching; a dropped network connection severing the SSE stream; calling session APIs before completing the create/attach handshake.
Related errors
- workspace closing
- invalid client_id
- server is shutting down
- server is hosting live workspaces
- client has been retired
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/3ed706e3890fd515.
Report an issue: GitHub.