{"record":{"id":"15a5c7de8a76596b","repo":"ruvnet/ruflo","slug":"invalid-label-value","errorCode":null,"errorMessage":"invalid ${label}: ${value}","messagePattern":"invalid (.+?): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/codex/src/worktrees/coordinator.ts","lineNumber":31,"sourceCode":"\nexport interface WorktreeRunRecord {\n  version: 1;\n  runId: string;\n  repoRoot: string;\n  createdAt: number;\n  assignments: WorktreeAssignment[];\n}\n\nfunction git(repoRoot: string, args: string[]): string {\n  return execFileSync('git', ['-C', repoRoot, ...args], {\n    encoding: 'utf8',\n    stdio: ['ignore', 'pipe', 'pipe'],\n    maxBuffer: 4 * 1024 * 1024,\n  }).trim();\n}\n\nfunction assertId(value: string, label: string): void {\n  if (!SAFE_ID.test(value)) throw new Error(`invalid ${label}: ${value}`);\n}\n\nexport class CodexWorktreeCoordinator {\n  readonly repoRoot: string;\n  readonly registryDir: string;\n  readonly worktreeBase: string;\n\n  constructor(repoRoot: string) {\n    this.repoRoot = resolve(repoRoot);\n    const top = git(this.repoRoot, ['rev-parse', '--show-toplevel']);\n    if (resolve(top) !== this.repoRoot) throw new Error(`repoRoot must be the git top-level: ${top}`);\n    this.registryDir = join(this.repoRoot, '.claude-flow', 'swarm', 'worktrees');\n    this.worktreeBase = join(dirname(this.repoRoot), '.ruflo-worktrees', basename(this.repoRoot));\n  }\n\n  prepare(\n    runId: string,\n    agents: Array<{ id: string; readOnly?: boolean }>,","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/codex/src/worktrees/coordinator.ts#L13-L49","documentation":"The worktree coordinator uses assertId() to validate run ids and agent ids against SAFE_ID = /^[a-z0-9][a-z0-9._-]{0,63}$/: lowercase alphanumerics, dots, underscores, hyphens; must start with a letter/digit; max 64 chars. Ids become directory names and registry keys, so anything else (uppercase, slashes, '..', spaces, unicode, empty, >64 chars) is rejected with 'invalid <run id|agent id>: <value>'.","triggerScenarios":"prepare('Run/1', ...) or agent ids like 'Agent Alpha', '../escape', 'Ünicode-id', '', or a 70-char id; ids generated with uuid (uppercase hex) or containing path separators.","commonSituations":"Callers reuse display names or uuids as agent ids; ids derived from branch names with slashes; usernames with spaces; accidental uppercase from copy-paste.","solutions":["Normalize ids before calling: lowercase, replace unsafe chars with '-', trim to 64 chars, ensure it starts with [a-z0-9]","Prefer short slugs like 'agent-1', 'coder-2', 'run-20260818'","Validate in your own code with the same regex so the error surfaces at the source"],"exampleFix":"// before\ncoordinator.prepare('Run #1', [{ id: 'Coder/Alpha' }]); // throws\n// after\nconst SAFE_ID = /^[a-z0-9][a-z0-9._-]{0,63}$/;\nconst slug = (s: string) => s.toLowerCase().replace(/[^a-z0-9._-]+/g, '-').slice(0, 64);\ncoordinator.prepare(slug('run-1'), [{ id: slug('coder-alpha') }]);","handlingStrategy":"type-guard","validationCode":"const SAFE_ID = /^[a-z0-9][a-z0-9._-]{0,63}$/;\nconst okId = (s: string) => SAFE_ID.test(s);","typeGuard":"const SAFE_ID = /^[a-z0-9][a-z0-9._-]{0,63}$/;\nfunction isSafeId(v: unknown): v is string {\n  return typeof v === 'string' && SAFE_ID.test(v);\n}","tryCatchPattern":"try { coordinator.prepare(runId, agents); } catch (e) { if (/^invalid (run|agent) id/.test(String(e))) throw new TypeError(`normalize ids: ${e.message}`); throw e; }","preventionTips":["Generate ids as slugs: lowercase, [a-z0-9._-], <=64 chars, leading letter/digit","Never reuse display names, uuids, or branch names as agent ids unchecked","Slugify at the boundary where human names become machine ids"],"tags":["validation","identifier","worktrees","security"],"backgroundTag":"invalid-identifier","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}