{"record":{"id":"ce31945565e72318","repo":"different-ai/openwork","slug":"name-must-be-a-safe-integer-greater-than-or-equ","errorCode":null,"errorMessage":"${name} must be a safe integer greater than or equal to ${minimum}.","messagePattern":"(.+?) must be a safe integer greater than or equal to (.+?)\\.","errorType":"validation","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"packages/codemode/src/codemode.ts","lineNumber":127,"sourceCode":"/** Schema for the structured success or diagnostic returned by CodeMode execution. */\nexport const Result = Schema.Union([Success, Failure])\n/** Result of executing a CodeMode program. Program failures are data, not Effect failures. */\nexport type Result = typeof Result.Type\n\n/** Reusable confined runtime over one explicit tool tree. */\nexport type Runtime<R = never> = {\n  readonly catalog: () => ReadonlyArray<ToolDescription>\n  readonly instructions: () => string\n  readonly execute: (code: string) => Effect.Effect<Result, never, R>\n}\n\nconst validateLimit = <Value extends number | undefined>(\n  name: keyof ExecutionLimits,\n  value: Value,\n  minimum: number,\n): Value => {\n  if (value !== undefined && (!Number.isSafeInteger(value) || value < minimum)) {\n    throw new RangeError(`${name} must be a safe integer greater than or equal to ${minimum}.`)\n  }\n  return value\n}\n\nconst resolveExecutionLimits = (limits?: ExecutionLimits): ResolvedExecutionLimits => ({\n  timeoutMs: validateLimit(\"timeoutMs\", limits?.timeoutMs, 1),\n  maxToolCalls: validateLimit(\"maxToolCalls\", limits?.maxToolCalls, 0),\n  maxOutputBytes: validateLimit(\"maxOutputBytes\", limits?.maxOutputBytes, 0),\n})\n\n/** Executes one Effect-native CodeMode program without constructing a reusable runtime. */\nexport const execute = <const Tools extends Record<string, unknown>>(\n  options: ExecuteOptions<Tools>,\n): Effect.Effect<Result, never, Services<Tools>> => {\n  const tools = (options.tools ?? {}) as HostTools<Services<Tools>>\n  ToolRuntime.assertValidTools(tools)\n  return executeWithLimits(options, resolveExecutionLimits(options.limits), ToolRuntime.searchIndex(tools))\n}","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/packages/codemode/src/codemode.ts#L109-L145","documentation":"validateLimit checks optional ExecutionLimits fields (timeoutMs, etc.) during resolveExecutionLimits. Any provided value must be a safe integer >= the field's minimum (timeoutMs >= 1). Undefined is allowed (falls back to defaults), but anything non-integral, negative, zero where 1 is required, or beyond Number.MAX_SAFE_INTEGER throws a RangeError naming the field and minimum.","triggerScenarios":"Passing limits like { timeoutMs: 0 }, { timeoutMs: 1.5 }, { timeoutMs: NaN }, { timeoutMs: \"5000\" } (string), or a value < the field minimum into resolveExecutionLimits / the codemode execution options.","commonSituations":"Loading limits from env vars or JSON config without Number coercion; computing a timeout with arithmetic that yields NaN; setting 0 intending 'unlimited' when 1 is the minimum.","solutions":["Coerce config values with Number() and ensure integer >= 1 before passing (e.g. Math.max(1, Math.floor(ms)))","Omit the field (undefined) to use library defaults instead of passing 0","Validate env/JSON-derived values in your config loader with Number.isSafeInteger"],"exampleFix":"// before\nresolveExecutionLimits({ timeoutMs: process.env.TIMEOUT_MS }) // string\n// after\nconst t = Number(process.env.TIMEOUT_MS)\nresolveExecutionLimits({ timeoutMs: Number.isSafeInteger(t) && t >= 1 ? t : undefined })","handlingStrategy":"validation","validationCode":"function parseLimit(v: unknown, min = 1): number | undefined {\n  const n = typeof v === \"string\" ? Number(v) : v\n  if (n === undefined || n === null) return undefined\n  if (typeof n !== \"number\" || !Number.isSafeInteger(n) || n < min) {\n    throw new Error(`Limit must be a safe integer >= ${min}`)\n  }\n  return n\n}\nresolveExecutionLimits({ timeoutMs: parseLimit(raw.timeoutMs) })","typeGuard":"const isSafeLimit = (v: unknown): v is number =>\n  typeof v === \"number\" && Number.isSafeInteger(v) && v >= 1","tryCatchPattern":"try {\n  limits = resolveExecutionLimits(userLimits)\n} catch (e) {\n  if (e instanceof RangeError && e.message.includes(\"safe integer\")) {\n    limits = resolveExecutionLimits(undefined) // fall back to defaults\n  } else throw e\n}","preventionTips":["Coerce env/JSON config numbers explicitly with Number() in your config loader","Use Math.max(1, Math.floor(ms)) when deriving limits from arithmetic","Omit the field instead of passing 0; 0 is below every minimum","Type-limit inputs with zod (z.number().int().min(1)) at the config boundary"],"tags":["validation","configuration","limits"],"backgroundTag":"invalid-numeric-option","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}