can1357/oh-my-pi · error · Error

maxAgents must be a positive integer

Error message

maxAgents must be a positive integer

What it means

runCleanseLoop performs the same internal validation as runCleanse: CleanseLoopOptions.maxAgents must be a positive integer. This is the loop-level guard so direct callers of the loop API cannot bypass the CLI-level check.

Source

Thrown at packages/coding-agent/src/cleanse/loop.ts:77

/**
 * Stream diagnostics into a bounded worker pool, then verify the combined edits.
 *
 * Diagnostics are grouped per file and dispatched as they arrive: a new file
 * group goes to a fresh worker while fewer than `maxAgents` run; otherwise it
 * queues until a slot frees. Files stay sticky — two workers never edit the
 * same file concurrently. Late diagnostics for an owned file are steered into
 * the owning worker's chat via `followUp`; when that fails (worker not yet
 * registered or already finishing) they are requeued for a fresh worker once
 * the owner releases the file. Each diagnostic is dispatched at most once;
 * the final verification pass decides `clean`.
 */
export async function runCleanseLoop(
	options: CleanseLoopOptions,
	dependencies: CleanseLoopDependencies,
): Promise<CleanseLoopResult> {
	const { maxAgents, signal } = options;
	if (!Number.isInteger(maxAgents) || maxAgents <= 0) {
		throw new Error("maxAgents must be a positive integer");
	}

	const seen = new Set<string>();
	/** File key (`""` = project-level) → queued diagnostics not yet assigned. */
	const pending = new Map<string, CleanseDiagnostic[]>();
	/** File keys owned by an in-flight worker. */
	const owned = new Map<string, OwnerEntry>();
	const inFlight = new Map<number, { assignment: CleanseAssignment; done: Promise<void> }>();
	const followUps = new Set<Promise<void>>();
	const outcomes: CleanseAgentOutcome[] = [];
	let dispatched = 0;
	/** Infrastructure failure from the dispatch seam (subagent errors settle as outcomes instead). */
	let dispatchFailure: unknown;

	/** Queue one deduplicated diagnostic: held for its owner or pending for a fresh worker. */
	const route = (diagnostic: CleanseDiagnostic, touched: Set<OwnerEntry>): void => {
		const fileKey = diagnostic.file ?? "";
		const entry = owned.get(fileKey);

View on GitHub (pinned to 9690622007)

Solutions

  1. Provide options.maxAgents as a positive integer before calling runCleanseLoop.
  2. Mirror the CLI validation in your wrapper before constructing CleanseLoopOptions.
  3. Use the same default as runCleanse (32) when the caller did not specify a value.

Example fix

// before
await runCleanseLoop({ signal, diagnostics }, deps); // maxAgents missing
// after
await runCleanseLoop({ signal, diagnostics, maxAgents: 32 }, deps);
Defensive patterns

Strategy: validation

Validate before calling

if (!Number.isInteger(options.maxAgents) || options.maxAgents <= 0) {
  throw new Error("maxAgents must be a positive integer");
}
await runCleanseLoop(options, deps);

Type guard

function hasValidMaxAgents(o: { maxAgents?: number }): o is { maxAgents: number } & typeof o {
  return Number.isInteger(o.maxAgents) && (o.maxAgents as number) > 0;
}

Try / catch

try {
  const result = await runCleanseLoop(loopOptions, deps);
} catch (err) {
  if (err instanceof Error && err.message.includes("maxAgents must be a positive integer")) {
    loopOptions.maxAgents = 32;
    // retry with default or abort
  } else throw err;
}

Prevention

When it happens

Trigger: Invoking runCleanseLoop with options.maxAgents undefined, 0, negative, non-integer, or NaN — typically when calling the loop API directly (tests/programmatic use) instead of through runCleanse.

Common situations: Programmatic/SDK use of the cleanse loop where options are constructed by hand or deserialized from JSON that omitted maxAgents.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — 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/1c84d00c4b745774. Report an issue: GitHub.