can1357/oh-my-pi · error

--agents must be a positive integer

Error message

--agents must be a positive integer

What it means

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.

Source

Thrown at packages/coding-agent/src/compress/index.ts:81

				matched += 1;
			}
			if (matched === 0) throw new Error(`No files matched "${pattern}"`);
			continue;
		}
		const resolved = path.resolve(cwd, pattern);
		const stat = await fs.stat(resolved).catch(() => undefined);
		if (!stat?.isFile()) throw new Error(`Not a file: ${shortenPath(resolved)}`);
		found.add(resolved);
	}
	return [...found].sort();
}

/** Compress every requested file through the rewrite/approve loop. */
export async function runCompressCommand(options: CompressCommandOptions): Promise<CompressResult> {
	const maxRounds = options.maxRounds ?? DEFAULT_MAX_ROUNDS;
	const concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;
	if (!Number.isInteger(maxRounds) || maxRounds <= 0) throw new Error("--rounds must be a positive integer");
	if (!Number.isInteger(concurrency) || concurrency <= 0) throw new Error("--agents must be a positive integer");
	if (options.inPlace && options.output) throw new Error("--in-place and --out are mutually exclusive");
	// Paths and patterns follow the shell's cwd, as a file-taking CLI must; the project
	// dir only scopes settings discovery for the sessions.
	const invocationDir = process.cwd();
	const cwd = getProjectDir();
	const targets = await resolveCompressTargets(options.files, invocationDir);
	if (targets.length === 0) throw new Error("No files to compress");
	if (targets.length > 1 && !options.inPlace) {
		throw new Error(`${targets.length} files matched; pass --in-place to rewrite them (--out takes a single file)`);
	}

	const abortController = new AbortController();
	const abort = (): void => abortController.abort(new Error("Compress interrupted"));
	process.once("SIGINT", abort);
	process.once("SIGTERM", abort);
	const progress = createProgressReporter("Compressing");
	const emitToStdout = targets.length === 1 && !options.inPlace && options.output === undefined;

View on GitHub (pinned to 9690622007)

Solutions

  1. Pass a positive integer, e.g. `--agents 4`.
  2. Check the script/env supplying the value; guard with `${JOBS:-1}` in shell.
  3. Omit the flag to use the default concurrency.
  4. Coerce/validate programmatically: Number.isInteger(n) && n > 0 before calling.

Example fix

// before
omp compress file.ts --agents $UNSET   // expands to empty
// after
omp compress file.ts --agents "${AGENTS:-2}"
Defensive patterns

Strategy: validation

Validate before calling

function validAgents(v: unknown): v is number {
  return typeof v === "number" && Number.isInteger(v) && v > 0;
}
if (!validAgents(concurrency)) throw new Error("--agents must be a positive integer");

Type guard

function isPositiveInt(v: unknown): v is number {
  return typeof v === "number" && Number.isInteger(v) && v > 0;
}

Try / catch

try {
  await runCompressCommand({ ...options, concurrency });
} catch (err) {
  if (err instanceof Error && err.message === "--agents must be a positive integer") {
    process.stderr.write(`${err.message} (got: ${String(options.concurrency)})\n`);
  } else throw err;
}

Prevention

When it happens

Trigger: Invoking compress with `--agents 0`, `--agents -2`, `--agents many`, `--agents 2.5`, or programmatically supplying a non-integer options.concurrency.

Common situations: 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.

Understand the failure class

Background: "Unknown argument", "Invalid value", and "must be one of": invalid CLI argument errors explained — this error's family across 35 libraries.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/3e711c4893e8b70b. Report an issue: GitHub.