{"record":{"id":"1cf497dad30971a6","repo":"github/copilot-sdk","slug":"factory-limit-field-must-be-a-positive-intege","errorCode":null,"errorMessage":"Factory limit \"${field}\" must be a positive integer","messagePattern":"Factory limit \"(.+?)\" must be a positive integer","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nodejs/src/factory.ts","lineNumber":428,"sourceCode":"    if (value !== null && typeof value === \"object\" && !Object.isFrozen(value)) {\n        Object.freeze(value);\n        for (const nested of Object.values(value)) {\n            deepFreeze(nested);\n        }\n    }\n    return value;\n}\n\nfunction validateLimits(meta: FactoryMeta): void {\n    const limits = meta.limits;\n    if (!limits) {\n        return;\n    }\n\n    for (const field of [\"maxConcurrentSubagents\", \"maxTotalSubagents\"] as const) {\n        const value = limits[field];\n        if (value !== undefined && (!Number.isInteger(value) || value <= 0)) {\n            throw new Error(`Factory limit \"${field}\" must be a positive integer`);\n        }\n    }\n\n    if (\n        limits.timeoutSeconds !== undefined &&\n        (!Number.isFinite(limits.timeoutSeconds) || limits.timeoutSeconds <= 0)\n    ) {\n        throw new Error(\n            'Factory limit \"timeoutSeconds\" must be a positive, finite number of seconds'\n        );\n    }\n    if (\n        limits.timeoutSeconds !== undefined &&\n        limits.timeoutSeconds > MAX_FACTORY_TIMEOUT_SECONDS\n    ) {\n        throw new Error(\n            `Factory limit \"timeoutSeconds\" must not exceed ${MAX_FACTORY_TIMEOUT_SECONDS} seconds`\n        );","sourceCodeStart":410,"sourceCodeEnd":446,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/nodejs/src/factory.ts#L410-L446","documentation":"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.","triggerScenarios":"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().","commonSituations":"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).","solutions":["Provide positive whole numbers (>= 1) for both limit fields, or omit them entirely for defaults.","Coerce and validate external values: Number.parseInt + Number.isInteger before passing them in.","Use undefined (not 0) to express 'no explicit cap'.","Validate config values at startup with the same checks the factory performs."],"exampleFix":"// before\ndefineFactory({ limits: { maxConcurrentSubagents: Number(process.env.MAX_SUBAGENTS) } }); // \"0\"/\"\" -> throws\n// after\nconst n = Number.parseInt(process.env.MAX_SUBAGENTS ?? '', 10);\ndefineFactory({ limits: Number.isInteger(n) && n > 0 ? { maxConcurrentSubagents: n } : {} });","handlingStrategy":"validation","validationCode":"function assertPositiveInt(v: unknown, name: string): void {\n  if (v !== undefined && (!Number.isInteger(v) || (v as number) <= 0)) {\n    throw new Error(`Factory limit \"${name}\" must be a positive integer`);\n  }\n}\nassertPositiveInt(limits.maxConcurrentSubagents, 'maxConcurrentSubagents');\nassertPositiveInt(limits.maxTotalSubagents, 'maxTotalSubagents');","typeGuard":"const isPositiveInt = (v: unknown): v is number =>\n  typeof v === 'number' && Number.isInteger(v) && v > 0;","tryCatchPattern":"try {\n  defineFactory({ limits });\n} catch (e) {\n  if (e instanceof Error && e.message.includes('must be a positive integer')) {\n    limits = {}; // fall back to defaults\n  } else throw e;\n}","preventionTips":["Parse numeric env/config values with Number.parseInt/Number before passing them in.","Omit a limit field entirely instead of using 0 for 'unlimited'.","Validate limits with Number.isInteger + > 0 at config load time.","Beware fractional arithmetic results when computing limits dynamically."],"tags":["validation","configuration","limits"],"backgroundTag":"invalid-argument-value","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}