{"record":{"id":"1fbf0aa37a6f5498","repo":"charmbracelet/crush","slug":"errinvalidclientid","errorCode":"ErrInvalidClientID","errorMessage":"%w: %v","messagePattern":"%w: %v","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/backend.go","lineNumber":1064,"sourceCode":"func resolveWorkspaceKey(path string) (string, error) {\n\tabs, err := filepath.Abs(path)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif resolved, err := filepath.EvalSymlinks(abs); err == nil {\n\t\treturn resolved, nil\n\t}\n\treturn abs, nil\n}\n\n// validateClientID returns the trimmed UUID string or an error if the\n// input is empty or not a valid UUID.\nfunc validateClientID(id string) (string, error) {\n\tif id == \"\" {\n\t\treturn \"\", ErrInvalidClientID\n\t}\n\tif _, err := uuid.Parse(id); err != nil {\n\t\treturn \"\", fmt.Errorf(\"%w: %v\", ErrInvalidClientID, err)\n\t}\n\treturn id, nil\n}\n\nfunc workspaceToProto(ws *Workspace) proto.Workspace {\n\tcfg := ws.Cfg.Config()\n\tout := proto.Workspace{\n\t\tID:       ws.ID,\n\t\tPath:     ws.Path,\n\t\tYOLO:     ws.Cfg.Overrides().SkipPermissionRequests,\n\t\tChannels: ws.Cfg.Overrides().EnabledChannels,\n\t\tDataDir:  cfg.Options.DataDirectory,\n\t\tDebug:    cfg.Options.Debug,\n\t\tConfig:   cfg,\n\t\tEnv:      ws.Env,\n\t\tVersion:  version.Version,\n\t}\n\tif ws.Skills != nil {","sourceCodeStart":1046,"sourceCodeEnd":1082,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/backend/backend.go#L1046-L1082","documentation":"validateClientID checks that a client-supplied ID is a non-empty valid UUID. An empty string returns bare ErrInvalidClientID; a non-empty but unparseable value returns ErrInvalidClientID wrapped with the uuid parse error via %w, so callers can errors.Is against ErrInvalidClientID.","triggerScenarios":"CreateWorkspace, AttachClient, RetireClient, releaseHold, or SetCurrentSession called with an empty or malformed client ID string (e.g. 'abc', truncated UUID, wrong casing is fine but wrong format is not).","commonSituations":"Client generates IDs with a non-UUID scheme; passing a session ID where a client ID is expected; empty field in an RPC payload; hand-crafted requests against the backend API.","solutions":["Send a proper UUIDv4 string as the client ID (e.g. uuid.New().String())","Check the client is not sending an empty/unset ID field","Confirm you're not confusing session IDs with client IDs"],"exampleFix":"// before\nclientID := \"my-client-1\"\n// after\nclientID := uuid.New().String()","handlingStrategy":"validation","validationCode":"func validClientID(id string) bool {\n    if id == \"\" {\n        return false\n    }\n    _, err := uuid.Parse(id)\n    return err == nil\n}","typeGuard":"func isValidUUID(s string) bool {\n    if s == \"\" {\n        return false\n    }\n    _, err := uuid.Parse(s)\n    return err == nil\n}","tryCatchPattern":"if _, err := b.AttachClient(ctx, clientID); err != nil {\n    if errors.Is(err, backend.ErrInvalidClientID) {\n        return fmt.Errorf(\"client ID must be a non-empty UUID: %w\", err)\n    }\n    return err\n}","preventionTips":["Generate client IDs with uuid.New().String()","Never pass session IDs or custom slugs where a client UUID is expected","Validate UUID format on the client before sending RPCs"],"tags":["validation","uuid","client"],"backgroundTag":"invalid-uuid","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}