{"record":{"id":"68bd745d95834469","repo":"github/copilot-sdk","slug":"factory-limit-maxaicredits-must-be-a-positive-f","errorCode":null,"errorMessage":"Factory limit \"maxAiCredits\" must be a positive, finite number that rounds to a safe positive integer nano-AIU ceiling","messagePattern":"Factory limit \"maxAiCredits\" must be a positive, finite number that rounds to a safe positive integer nano-AIU ceiling","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nodejs/src/factory.ts","lineNumber":457,"sourceCode":"    }\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        );\n    }\n\n    if (limits.maxAiCredits !== undefined) {\n        const maxNanoAiu = Math.round(limits.maxAiCredits * NANO_AIU_PER_AIU);\n        if (\n            !Number.isFinite(limits.maxAiCredits) ||\n            limits.maxAiCredits <= 0 ||\n            !Number.isSafeInteger(maxNanoAiu) ||\n            maxNanoAiu < 1\n        ) {\n            throw new Error(\n                'Factory limit \"maxAiCredits\" must be a positive, finite number that rounds to a safe positive integer nano-AIU ceiling'\n            );\n        }\n    }\n}\n\nfunction validatePhases(meta: FactoryMeta): void {\n    const titles = new Set<string>();\n    for (const phase of meta.phases) {\n        if (phase.title.trim().length === 0) {\n            throw new Error(\"Factory phase titles must not be empty\");\n        }\n        if (titles.has(phase.title)) {\n            throw new Error(`Factory phase title \"${phase.title}\" is declared more than once`);\n        }\n        titles.add(phase.title);\n    }\n}","sourceCodeStart":439,"sourceCodeEnd":475,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/nodejs/src/factory.ts#L439-L475","documentation":"This error is thrown by validateLimits when maxAiCredits is not a positive finite number, or when the value multiplied by NANO_AIU_PER_AIU and rounded does not yield a safe positive integer nano-AIU ceiling. The runtime tracks AI credit budgets in nano-AIU (integer units), so the configured credit value must map cleanly onto that integer representation.","triggerScenarios":"Calling defineFactory with limits.maxAiCredits set to 0, a negative number, NaN, or Infinity; or with a fractional value so small that Math.round(maxAiCredits * NANO_AIU_PER_AIU) rounds to 0 (below the representable minimum); or so large that it exceeds Number.MAX_SAFE_INTEGER in nano-AIU.","commonSituations":"Passing a decimal like 0.0000001 that rounds to zero nano-AIU; NaN from a failed config parse; Infinity from an attempted 'unlimited' setting; extremely large budgets overflowing the safe integer range.","solutions":["Pass a positive finite maxAiCredits large enough to round to at least 1 nano-AIU, e.g. 1.","Replace Infinity/0 sentinel values with a concrete positive budget.","Validate the value with Number.isFinite before calling defineFactory.","Choose a smaller value if the converted nano-AIU total exceeds Number.MAX_SAFE_INTEGER."],"exampleFix":"// before\ndefineFactory({ name: 'agent', limits: { maxAiCredits: Infinity } });\n// after\ndefineFactory({ name: 'agent', limits: { maxAiCredits: 100 } });","handlingStrategy":"validation","validationCode":"function isValidCredits(c) {\n  const maxNanoAiu = Math.round(c * NANO_AIU_PER_AIU);\n  return Number.isFinite(c) && c > 0 && Number.isSafeInteger(maxNanoAiu) && maxNanoAiu >= 1;\n}\nif (!isValidCredits(opts.limits?.maxAiCredits)) throw new TypeError('maxAiCredits must map to a safe positive integer nano-AIU ceiling');","typeGuard":"function hasValidCredits(l) { return l.maxAiCredits === undefined || (Number.isFinite(l.maxAiCredits) && l.maxAiCredits > 0); }","tryCatchPattern":"try {\n  defineFactory({ ...meta, limits: { maxAiCredits: credits } });\n} catch (e) {\n  if (String(e.message).includes('maxAiCredits')) console.error('Bad maxAiCredits:', credits);\n  throw e;\n}","preventionTips":["Use whole credit values; avoid tiny fractions that round to 0 nano-AIU","Never use Infinity as 'unlimited' — pick a concrete budget","Validate budget config at startup with Number.isFinite checks"],"tags":["validation","factory","configuration","credits"],"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-15T23:17:13.987Z"}