{"record":{"id":"bc8e6f6dd0d20231","repo":"charmbracelet/crush","slug":"invalid-client-id","errorCode":null,"errorMessage":"invalid client_id","messagePattern":"invalid client_id","errorType":"validation","errorClass":"ErrInvalidClientID","httpStatus":null,"severity":"error","filePath":"internal/backend/backend.go","lineNumber":37,"sourceCode":"\t\"github.com/charmbracelet/crush/internal/config\"\n\t\"github.com/charmbracelet/crush/internal/csync\"\n\t\"github.com/charmbracelet/crush/internal/db\"\n\t\"github.com/charmbracelet/crush/internal/proto\"\n\t\"github.com/charmbracelet/crush/internal/skills\"\n\t\"github.com/charmbracelet/crush/internal/ui/util\"\n\t\"github.com/charmbracelet/crush/internal/version\"\n\t\"github.com/google/uuid\"\n)\n\n// Common errors returned by backend operations.\nvar (\n\tErrWorkspaceNotFound       = errors.New(\"workspace not found\")\n\tErrLSPClientNotFound       = errors.New(\"LSP client not found\")\n\tErrAgentNotInitialized     = errors.New(\"agent coordinator not initialized\")\n\tErrPathRequired            = errors.New(\"path is required\")\n\tErrInvalidPermissionAction = errors.New(\"invalid permission action\")\n\tErrUnknownCommand          = errors.New(\"unknown command\")\n\tErrInvalidClientID         = errors.New(\"invalid client_id\")\n\tErrClientNotAttached       = errors.New(\"client not attached\")\n\tErrWorkspaceClosing        = errors.New(\"workspace closing\")\n\tErrServerShuttingDown      = errors.New(\"server is shutting down\")\n\tErrServerNotIdle           = errors.New(\"server is hosting live workspaces\")\n\tErrClientRetired           = errors.New(\"client has been retired\")\n\tErrChannelOptInMismatch    = errors.New(\"requested channels differ from the existing workspace; channels are an explicit opt-in and are not shared across duplicate creates\")\n)\n\n// DefaultCreateGrace is the window in which a client must open an SSE\n// stream after creating a workspace before its creation hold is\n// released. Exposed as a package variable so tests can shorten it.\nvar DefaultCreateGrace = 30 * time.Second\n\n// DefaultIdleShutdownDelay is how long the server stays alive after its\n// last workspace is released before it shuts itself down. The delay\n// exists so a client that closes one session and opens another moments\n// later (the same directory or a different one) reuses the still-running\n// server instead of racing its shutdown: with an immediate shutdown the","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/backend/backend.go#L19-L55","documentation":"ErrInvalidClientID reports that a client identifier supplied to a backend operation failed validation. The backend requires every client to present a well-formed client_id when attaching to or acting on a workspace, and validateClientID rejects anything malformed. It is declared as a public sentinel in internal/backend/backend.go so callers can match it with errors.Is.","triggerScenarios":"Calling AttachClient, DeleteWorkspace, or CreateWorkspace with an empty, whitespace-only, or malformed client_id; TestAttachClient_InvalidID and TestDeleteWorkspace_RejectsBadClientID exercise exactly these paths via validateClientID.","commonSituations":"Passing an empty string instead of a generated client ID, forgetting to persist a previously generated client_id across reconnects, or hand-rolling an ID with illegal characters instead of a UUID.","solutions":["Generate a non-empty client_id (e.g. uuid.NewString()) before calling any backend API","Verify validateClientID's expected format and conform your ID to it","Check that your client_id variable is actually populated (no zero-value struct field) before the call"],"exampleFix":"// before\nws, err := backend.AttachClient(ctx, \"\", path)\n// after\nclientID := uuid.NewString()\nws, err := backend.AttachClient(ctx, clientID, path)","handlingStrategy":"validation","validationCode":"func validClientID(id string) bool {\n    if _, err := uuid.Parse(id); err != nil {\n        return false\n    }\n    return strings.TrimSpace(id) != \"\"\n}\nif !validClientID(clientID) {\n    clientID = uuid.NewString()\n}","typeGuard":"func isErrInvalidClientID(err error) bool {\n    return errors.Is(err, backend.ErrInvalidClientID)\n}","tryCatchPattern":null,"preventionTips":["Always generate client IDs with uuid.NewString() at client startup","Persist the client_id only for the lifetime of a single server connection","Never pass zero-value strings from config into backend APIs"],"tags":["validation","backend","client-id"],"backgroundTag":"invalid-client-id","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}