different-ai/openwork · error · RangeError
${name} must be a safe integer greater than or equal to ${mi
Error message
${name} must be a safe integer greater than or equal to ${minimum}. What it means
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.
Source
Thrown at packages/codemode/src/codemode.ts:127
/** Schema for the structured success or diagnostic returned by CodeMode execution. */
export const Result = Schema.Union([Success, Failure])
/** Result of executing a CodeMode program. Program failures are data, not Effect failures. */
export type Result = typeof Result.Type
/** Reusable confined runtime over one explicit tool tree. */
export type Runtime<R = never> = {
readonly catalog: () => ReadonlyArray<ToolDescription>
readonly instructions: () => string
readonly execute: (code: string) => Effect.Effect<Result, never, R>
}
const validateLimit = <Value extends number | undefined>(
name: keyof ExecutionLimits,
value: Value,
minimum: number,
): Value => {
if (value !== undefined && (!Number.isSafeInteger(value) || value < minimum)) {
throw new RangeError(`${name} must be a safe integer greater than or equal to ${minimum}.`)
}
return value
}
const resolveExecutionLimits = (limits?: ExecutionLimits): ResolvedExecutionLimits => ({
timeoutMs: validateLimit("timeoutMs", limits?.timeoutMs, 1),
maxToolCalls: validateLimit("maxToolCalls", limits?.maxToolCalls, 0),
maxOutputBytes: validateLimit("maxOutputBytes", limits?.maxOutputBytes, 0),
})
/** Executes one Effect-native CodeMode program without constructing a reusable runtime. */
export const execute = <const Tools extends Record<string, unknown>>(
options: ExecuteOptions<Tools>,
): Effect.Effect<Result, never, Services<Tools>> => {
const tools = (options.tools ?? {}) as HostTools<Services<Tools>>
ToolRuntime.assertValidTools(tools)
return executeWithLimits(options, resolveExecutionLimits(options.limits), ToolRuntime.searchIndex(tools))
}View on GitHub (pinned to 2b7df46e8a)
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
Example fix
// before
resolveExecutionLimits({ timeoutMs: process.env.TIMEOUT_MS }) // string
// after
const t = Number(process.env.TIMEOUT_MS)
resolveExecutionLimits({ timeoutMs: Number.isSafeInteger(t) && t >= 1 ? t : undefined }) Defensive patterns
Strategy: validation
Validate before calling
function parseLimit(v: unknown, min = 1): number | undefined {
const n = typeof v === "string" ? Number(v) : v
if (n === undefined || n === null) return undefined
if (typeof n !== "number" || !Number.isSafeInteger(n) || n < min) {
throw new Error(`Limit must be a safe integer >= ${min}`)
}
return n
}
resolveExecutionLimits({ timeoutMs: parseLimit(raw.timeoutMs) }) Type guard
const isSafeLimit = (v: unknown): v is number => typeof v === "number" && Number.isSafeInteger(v) && v >= 1
Try / catch
try {
limits = resolveExecutionLimits(userLimits)
} catch (e) {
if (e instanceof RangeError && e.message.includes("safe integer")) {
limits = resolveExecutionLimits(undefined) // fall back to defaults
} else throw e
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- DEN_API_PUBLIC_URL cannot contain credentials, a query strin
- Manual OIDC configuration requires authorization, token, and
- Invalid IANA timezone: ${timezone}
- An enterprise MCP server URL must use HTTP or HTTPS.
- An enterprise MCP server URL cannot contain a fragment.
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/ce31945565e72318.
Report an issue: GitHub.