{"record":{"id":"3e711c4893e8b70b","repo":"can1357/oh-my-pi","slug":"agents-must-be-a-positive-integer-3e711c","errorCode":null,"errorMessage":"--agents must be a positive integer","messagePattern":"--agents must be a positive integer","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/compress/index.ts","lineNumber":81,"sourceCode":"\t\t\t\tmatched += 1;\n\t\t\t}\n\t\t\tif (matched === 0) throw new Error(`No files matched \"${pattern}\"`);\n\t\t\tcontinue;\n\t\t}\n\t\tconst resolved = path.resolve(cwd, pattern);\n\t\tconst stat = await fs.stat(resolved).catch(() => undefined);\n\t\tif (!stat?.isFile()) throw new Error(`Not a file: ${shortenPath(resolved)}`);\n\t\tfound.add(resolved);\n\t}\n\treturn [...found].sort();\n}\n\n/** Compress every requested file through the rewrite/approve loop. */\nexport async function runCompressCommand(options: CompressCommandOptions): Promise<CompressResult> {\n\tconst maxRounds = options.maxRounds ?? DEFAULT_MAX_ROUNDS;\n\tconst concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;\n\tif (!Number.isInteger(maxRounds) || maxRounds <= 0) throw new Error(\"--rounds must be a positive integer\");\n\tif (!Number.isInteger(concurrency) || concurrency <= 0) throw new Error(\"--agents must be a positive integer\");\n\tif (options.inPlace && options.output) throw new Error(\"--in-place and --out are mutually exclusive\");\n\t// Paths and patterns follow the shell's cwd, as a file-taking CLI must; the project\n\t// dir only scopes settings discovery for the sessions.\n\tconst invocationDir = process.cwd();\n\tconst cwd = getProjectDir();\n\tconst targets = await resolveCompressTargets(options.files, invocationDir);\n\tif (targets.length === 0) throw new Error(\"No files to compress\");\n\tif (targets.length > 1 && !options.inPlace) {\n\t\tthrow new Error(`${targets.length} files matched; pass --in-place to rewrite them (--out takes a single file)`);\n\t}\n\n\tconst abortController = new AbortController();\n\tconst abort = (): void => abortController.abort(new Error(\"Compress interrupted\"));\n\tprocess.once(\"SIGINT\", abort);\n\tprocess.once(\"SIGTERM\", abort);\n\tconst progress = createProgressReporter(\"Compressing\");\n\tconst emitToStdout = targets.length === 1 && !options.inPlace && options.output === undefined;\n","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/compress/index.ts#L63-L99","documentation":"runCompressCommand validates the concurrency option: concurrency (from --agents, default DEFAULT_CONCURRENCY) must be a positive integer. Non-integer, zero, or negative values throw before any files are processed. This keeps the parallel agent pool sized sanely.","triggerScenarios":"Invoking compress with `--agents 0`, `--agents -2`, `--agents many`, `--agents 2.5`, or programmatically supplying a non-integer options.concurrency.","commonSituations":"Shell arithmetic producing 0 or empty (`--agents $JOBS` where JOBS is unset); misunderstanding that 0 means 'unlimited'; scripts reading counts from config files as strings.","solutions":["Pass a positive integer, e.g. `--agents 4`.","Check the script/env supplying the value; guard with `${JOBS:-1}` in shell.","Omit the flag to use the default concurrency.","Coerce/validate programmatically: Number.isInteger(n) && n > 0 before calling."],"exampleFix":"// before\nomp compress file.ts --agents $UNSET   // expands to empty\n// after\nomp compress file.ts --agents \"${AGENTS:-2}\"","handlingStrategy":"validation","validationCode":"function validAgents(v: unknown): v is number {\n  return typeof v === \"number\" && Number.isInteger(v) && v > 0;\n}\nif (!validAgents(concurrency)) throw new Error(\"--agents must be a positive integer\");","typeGuard":"function isPositiveInt(v: unknown): v is number {\n  return typeof v === \"number\" && Number.isInteger(v) && v > 0;\n}","tryCatchPattern":"try {\n  await runCompressCommand({ ...options, concurrency });\n} catch (err) {\n  if (err instanceof Error && err.message === \"--agents must be a positive integer\") {\n    process.stderr.write(`${err.message} (got: ${String(options.concurrency)})\\n`);\n  } else throw err;\n}","preventionTips":["Always pass plain integers to --agents (e.g. 2, 4).","Guard shell interpolation: `--agents \"${AGENTS:-2}\"`.","Omit the flag to accept the default concurrency.","Coerce config-file strings to numbers and validate before passing programmatically."],"tags":["cli","argument-validation","configuration"],"backgroundTag":"invalid-cli-argument","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}