charmbracelet/crush · error · ErrChannelOptInMismatch

requested channels differ from the existing workspace; chann

Error message

requested channels differ from the existing workspace; channels are an explicit opt-in and are not shared across duplicate creates

What it means

ErrChannelOptInMismatch reports that a duplicate CreateWorkspace specified a set of channels that differs from the channels the existing workspace was created with. Channels are an explicit opt-in and are deliberately not shared across duplicate creates, so an existing workspace is never silently reconfigured. Returned by CreateWorkspace.

Source

Thrown at internal/backend/backend.go:43

	"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 is
// already tearing down, and then observe its coder agent as "offline".
// Any workspace create within the window cancels the pending shutdown.
// Overridable via CRUSH_SERVER_IDLE_TIMEOUT (seconds; 0 restores the
// old shut-down-immediately behavior).
var DefaultIdleShutdownDelay = 60 * time.Second

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Make the duplicate create request the same channel set the existing workspace was created with
  2. Delete the existing workspace first, then re-create with the desired channels
  3. Align channel configuration across all clients that share the working directory

Example fix

// before
ws, err := backend.CreateWorkspace(ctx, id, path, backend.WithChannels("events")) // existing ws has none
// after
ws, err := backend.DeleteWorkspace(ctx, id, path)
if err != nil { return err }
ws, err = backend.CreateWorkspace(ctx, id, path, backend.WithChannels("events"))
Defensive patterns

Strategy: validation

Validate before calling

if existing, ok := workspaceAt(path); ok && !slices.Equal(existing.Channels, requestedChannels) {
    // either drop the channels arg to match, or delete and re-create
    if err := backend.DeleteWorkspace(ctx, id, path); err != nil {
        return err
    }
}

Type guard

func isErrChannelOptInMismatch(err error) bool {
    return errors.Is(err, backend.ErrChannelOptInMismatch)
}

Try / catch

ws, err := backend.CreateWorkspace(ctx, id, path, opts...)
if errors.Is(err, backend.ErrChannelOptInMismatch) {
    // retry matching the existing workspace's channels
    ws, err = backend.CreateWorkspace(ctx, id, path, existingChannelsOpts...)
}
return err

Prevention

When it happens

Trigger: Calling CreateWorkspace with the same path and client when a workspace already exists at that path, but passing a different channels set than the original create (e.g. one call opts into a channel, the other does not).

Common situations: Two launch points (editor + CLI) creating workspaces for the same directory with differing channel configurations; config change between the first and second launch adding or removing an opted-in channel; a stale script pinned to old channel flags.

Related errors


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