{"record":{"id":"71ae5f324e123a82","repo":"Yeachan-Heo/oh-my-codex","slug":"invalid-task-id-taskid-must-be-a-positive-i","errorCode":null,"errorMessage":"Invalid task ID: \"${taskId}\". Must be a positive integer (digits only, max 20 digits).","messagePattern":"Invalid task ID: \"(.+?)\"\\. Must be a positive integer \\(digits only, max 20 digits\\)\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/team/state.ts","lineNumber":508,"sourceCode":"function assertPathWithinDir(filePath: string, rootDir: string): void {\n  const normalizedRoot = resolve(rootDir);\n  const normalizedPath = resolve(filePath);\n  if (normalizedPath !== normalizedRoot && !normalizedPath.startsWith(normalizedRoot + sep)) {\n    throw new Error('Path traversal detected: path is outside the allowed directory');\n  }\n}\n\nfunction validateWorkerName(name: string): void {\n  if (!WORKER_NAME_SAFE_PATTERN.test(name)) {\n    throw new Error(\n      `Invalid worker name: \"${name}\". Must match /^[a-z0-9][a-z0-9-]{0,63}$/ (lowercase alphanumeric + hyphens, max 64 chars).`\n    );\n  }\n}\n\nfunction validateTaskId(taskId: string): void {\n  if (!TASK_ID_SAFE_PATTERN.test(taskId)) {\n    throw new Error(\n      `Invalid task ID: \"${taskId}\". Must be a positive integer (digits only, max 20 digits).`\n    );\n  }\n}\n\nfunction defaultLeader(): TeamLeader {\n  return {\n    session_id: '',\n    worker_id: 'leader-fixed',\n    role: 'coordinator',\n  };\n}\n\nfunction defaultTmuxPaneOwnerId(teamName: string): string {\n  return `team:${teamName}`;\n}\n\nfunction defaultPolicy(","sourceCodeStart":490,"sourceCodeEnd":526,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/team/state.ts#L490-L526","documentation":"Task ID failed TASK_ID_SAFE_PATTERN: it must be a positive integer expressed as digits only, at most 20 digits (no signs, decimals, or non-numeric characters). Thrown by validateTaskId via taskClaimLockDir, approvalPath, and taskFilePath.","triggerScenarios":"Passing task ids like 'task-12', '12.0', '-5', a UUID, or an empty string to taskClaimLockDir, approvalPath, or taskFilePath.","commonSituations":"External systems using UUID or prefixed ids mapped directly to task ids; parsing ids from strings without stripping prefixes; numeric ids serialized as floats.","solutions":["Extract the numeric portion (e.g. parseInt/regex '^\\\\d+$') and pass it as a canonical decimal string","Validate ids at input boundaries with /^\\d{1,20}$/ before calling these APIs","Reject or remap non-numeric external identifiers instead of passing them through"],"exampleFix":"// before\nconst p = taskFilePath(`task-${id}`, ...); // throws\n\n// after\nconst numericId = String(id).replace(/^\\D+/, '');\nif (!/^\\d{1,20}$/.test(numericId)) throw new Error('invalid task id');\nconst p = taskFilePath(numericId, ...);","handlingStrategy":"type-guard","validationCode":"function normalizeTaskId(raw: string | number): string | null {\n  const s = typeof raw === 'number' ? String(Math.trunc(raw)) : raw;\n  return /^\\d{1,20}$/.test(s) && !/^0/.test(s) === false ? (s === '0' ? null : s) : (/^[1-9]\\d{0,19}$/.test(s) ? s : null);\n}","typeGuard":"function isValidTaskId(taskId: string): boolean {\n  return /^[1-9]\\d{0,19}$|^0$/.test(taskId) && /^\\d{1,20}$/.test(taskId);\n}","tryCatchPattern":null,"preventionTips":["Map external UUIDs to numeric task ids at the integration layer","Parse ids with strict numeric regex before calling task state APIs"],"tags":["team","validation","task-id","input-validation"],"backgroundTag":"identifier-validation-failed","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}