{"record":{"id":"ea1cbc7172877816","repo":"ruvnet/ruflo","slug":"maxconcurrency-must-be-a-positive-integer","errorCode":null,"errorMessage":"maxConcurrency must be a positive integer","messagePattern":"maxConcurrency must be a positive integer","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/services/bounded-worker-pool.ts","lineNumber":32,"sourceCode":"  results: BoundedTaskResult<T>[];\n  peakConcurrency: number;\n  durationMs: number;\n}\n\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;","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/services/bounded-worker-pool.ts#L14-L50","documentation":"runBoundedPool validates its options before starting any work: options.maxConcurrency must be an integer >= 1 (Number.isInteger rejects 0, negatives, NaN, Infinity, and fractional values). The pool exists to make Codex/MetaHarness fanout deterministic and bounded, so an invalid concurrency limit is a caller bug and fails fast rather than degrading to unbounded execution.","triggerScenarios":"Passing tasks.length as maxConcurrency when tasks is empty (0), reading concurrency from an env var or config without parsing ('4' is not an integer, undefined from a missing key), or computing it with arithmetic that yields NaN/fractional values (e.g. tasks.length / 2 without Math.floor).","commonSituations":"Dynamic fanout where the task list can be empty, config-driven concurrency with a typo'd key, division-based heuristics like Math.round(n/3) that can round to 0 for small n.","solutions":["Clamp and floor the value at the call site: const max = Math.max(1, Math.floor(Number(opts.concurrency) || DEFAULT))","If deriving from tasks.length, guard the empty case explicitly before calling runBoundedPool","Type the options object so maxConcurrency: number forces callers to resolve undefined/NaN earlier"],"exampleFix":"// before\nawait runBoundedPool(tasks, { maxConcurrency: tasks.length }); // throws when tasks is empty\n\n// after\nconst maxConcurrency = Math.max(1, Math.floor(Number(options.concurrency ?? 4)));\nconst results = tasks.length\n  ? await runBoundedPool(tasks, { maxConcurrency, timeoutMs: 30_000 })\n  : { results: [], cancelled: false, elapsedMs: 0 };","handlingStrategy":"validation","validationCode":"const raw = Number(config.concurrency); // from env/config\nconst maxConcurrency = Number.isInteger(raw) && raw >= 1 ? raw : 4; // safe default\nawait runBoundedPool(tasks, { maxConcurrency: Math.min(maxConcurrency, tasks.length || 1), timeoutMs: 30_000 });","typeGuard":"const isValidConcurrency = (v: unknown): v is number => typeof v === 'number' && Number.isInteger(v) && v >= 1;","tryCatchPattern":null,"preventionTips":["Never pass tasks.length unchecked — clamp with Math.max(1, ...)","Parse env/config concurrency once at load time with a validated default, not at each call site","Type options as { maxConcurrency: number } so undefined from optional config fails at compile time"],"tags":["worker-pool","concurrency","validation","bounded-execution"],"backgroundTag":"invalid-argument-value","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}