github/copilot-sdk · error

Factory limit " " must be a positive integer

Error message

Factory limit "${field}" must be a positive integer

What it means

defineFactory validates subagent limits at factory definition time. maxConcurrentSubagents and maxTotalSubagents, when provided, must be positive integers — they cap how many subagents may run concurrently and in total. Zero, negative, or non-integer values are meaningless caps and are rejected up front.

Solutions

  1. Provide positive whole numbers (>= 1) for both limit fields, or omit them entirely for defaults.
  2. Coerce and validate external values: Number.parseInt + Number.isInteger before passing them in.
  3. Use undefined (not 0) to express 'no explicit cap'.
  4. Validate config values at startup with the same checks the factory performs.

Example fix

// before
defineFactory({ limits: { maxConcurrentSubagents: Number(process.env.MAX_SUBAGENTS) } }); // "0"/"" -> throws
// after
const n = Number.parseInt(process.env.MAX_SUBAGENTS ?? '', 10);
defineFactory({ limits: Number.isInteger(n) && n > 0 ? { maxConcurrentSubagents: n } : {} });
Defensive patterns

Strategy: validation

Validate before calling

function assertPositiveInt(v: unknown, name: string): void {
  if (v !== undefined && (!Number.isInteger(v) || (v as number) <= 0)) {
    throw new Error(`Factory limit "${name}" must be a positive integer`);
  }
}
assertPositiveInt(limits.maxConcurrentSubagents, 'maxConcurrentSubagents');
assertPositiveInt(limits.maxTotalSubagents, 'maxTotalSubagents');

Type guard

const isPositiveInt = (v: unknown): v is number =>
  typeof v === 'number' && Number.isInteger(v) && v > 0;

Try / catch

try {
  defineFactory({ limits });
} catch (e) {
  if (e instanceof Error && e.message.includes('must be a positive integer')) {
    limits = {}; // fall back to defaults
  } else throw e;
}

Prevention

When it happens

Trigger: Passing limits.maxConcurrentSubagents or limits.maxTotalSubagents as 0, a negative number, a float (e.g. 2.5), NaN, or a numeric string like "5" when calling defineFactory()/validateLimits().

Common situations: Loading limits from config/env where values arrive as strings and are not parsed; computing a limit with arithmetic that yields 0 or a fraction; typos using 0 to mean 'unlimited' (omit the field instead).

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 github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/1cf497dad30971a6. Report an issue: GitHub.

Appendix: source

Thrown at nodejs/src/factory.ts:428

    if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
        Object.freeze(value);
        for (const nested of Object.values(value)) {
            deepFreeze(nested);
        }
    }
    return value;
}

function validateLimits(meta: FactoryMeta): void {
    const limits = meta.limits;
    if (!limits) {
        return;
    }

    for (const field of ["maxConcurrentSubagents", "maxTotalSubagents"] as const) {
        const value = limits[field];
        if (value !== undefined && (!Number.isInteger(value) || value <= 0)) {
            throw new Error(`Factory limit "${field}" must be a positive integer`);
        }
    }

    if (
        limits.timeoutSeconds !== undefined &&
        (!Number.isFinite(limits.timeoutSeconds) || limits.timeoutSeconds <= 0)
    ) {
        throw new Error(
            'Factory limit "timeoutSeconds" must be a positive, finite number of seconds'
        );
    }
    if (
        limits.timeoutSeconds !== undefined &&
        limits.timeoutSeconds > MAX_FACTORY_TIMEOUT_SECONDS
    ) {
        throw new Error(
            `Factory limit "timeoutSeconds" must not exceed ${MAX_FACTORY_TIMEOUT_SECONDS} seconds`
        );

View on GitHub (pinned to cd8cf15dc3)