{"record":{"id":"048b240da14f463f","repo":"ruvnet/ruflo","slug":"duplicate-or-empty-task-id-task-id","errorCode":null,"errorMessage":"duplicate or empty task id: ${task.id}","messagePattern":"duplicate or empty task id: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/services/bounded-worker-pool.ts","lineNumber":36,"sourceCode":"\n/**\n * Deterministic bounded worker pool for Codex/MetaHarness fanout.\n *\n * Completion order never affects result order. The caller-supplied AbortSignal\n * and timeout cancel both queued and cooperative running work. No unbounded\n * Promise.all is used.\n */\nexport async function runBoundedPool<T>(\n  tasks: readonly BoundedTask<T>[],\n  options: { maxConcurrency: number; timeoutMs?: number; signal?: AbortSignal },\n): Promise<BoundedPoolResult<T>> {\n  const started = Date.now();\n  if (!Number.isInteger(options.maxConcurrency) || options.maxConcurrency < 1) {\n    throw new Error('maxConcurrency must be a positive integer');\n  }\n  const ids = new Set<string>();\n  for (const task of tasks) {\n    if (!task.id || ids.has(task.id)) throw new Error(`duplicate or empty task id: ${task.id}`);\n    ids.add(task.id);\n  }\n  const maxConcurrency = Math.min(options.maxConcurrency, tasks.length || 1);\n  const controller = new AbortController();\n  const onAbort = () => controller.abort(options.signal?.reason ?? new Error('cancelled'));\n  options.signal?.addEventListener('abort', onAbort, { once: true });\n  const timer = options.timeoutMs && options.timeoutMs > 0\n    ? setTimeout(() => controller.abort(new Error('worker-pool-timeout')), options.timeoutMs)\n    : undefined;\n\n  const results = new Map<string, BoundedTaskResult<T>>();\n  let cursor = 0;\n  let active = 0;\n  let peakConcurrency = 0;\n\n  const worker = async (): Promise<void> => {\n    while (cursor < tasks.length) {\n      const taskIndex = cursor++;","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/v3/@claude-flow/cli/src/services/bounded-worker-pool.ts#L18-L54","documentation":"runBoundedPool walks all tasks up front and requires every task.id to be non-empty and unique within the batch. A duplicate or empty id throws before scheduling, preserving the invariant that result order maps to task ids deterministically. The check uses a Set, so the first repeat (or empty string) aborts the run.","triggerScenarios":"Two tasks sharing the same id (e.g., generated from an index that reset, or a non-unique key); a task with id '' (default when a field is missing); tasks built from a map without guaranteeing key uniqueness.","commonSituations":"Generating ids from filenames that collide; using array index as id but two tasks reference the same logical unit; refactoring that dropped the id assignment; concurrent producers appending to the same task list with overlapping keys.","solutions":["Generate ids from a guaranteed-unique source (crypto.randomUUID, or composite key like `${namespace}:${key}`).","Deduplicate tasks by id before calling runBoundedPool.","Validate non-empty and unique ids at the producer side."],"exampleFix":"// before: index-based ids collide after a refactor\ntasks.push({ id: item.name, run }); // two items share name -> throws\n\n// after: composite unique id\nimport { randomUUID } from 'node:crypto';\ntasks.push({ id: `${item.type}:${item.name}:${randomUUID()}`, run });","handlingStrategy":"validation","validationCode":"function dedupeTaskIds(tasks) {\n  const seen = new Set();\n  for (const t of tasks) {\n    if (!t.id || seen.has(t.id)) throw new Error(`duplicate or empty task id: ${t.id}`);\n    seen.add(t.id);\n  }\n  return tasks;\n}","typeGuard":"function tasksHaveUniqueIds(tasks): boolean {\n  const ids = tasks.map(t => t.id).filter(Boolean);\n  return ids.length === tasks.length && new Set(ids).size === ids.length;\n}","tryCatchPattern":null,"preventionTips":["Generate task ids from a guaranteed-unique source (crypto.randomUUID or composite key).","Dedupe tasks by id before submitting to the pool.","Validate ids at the producer so empty/duplicate ids never reach runBoundedPool."],"tags":["validation","worker-pool","uniqueness","api-contract"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}