Budibase/budibase · error · JsRequestTimeoutError
JS_REQUEST_TIMEOUT_ERROR
JS_REQUEST_TIMEOUT_ERROR
Error message
CPU time limit exceeded (${cpuMs}ms > ${this.isolateAccumulatedTimeout}ms) What it means
The isolated-vm JS runner enforces a cumulative CPU-time budget per isolate. Before executing code, execute() compares the isolate's consumed cpuTime (converted to ms) against isolateAccumulatedTimeout and throws JsRequestTimeoutError (code JS_REQUEST_TIMEOUT_ERROR) when the budget is exhausted, preventing runaway scripts from consuming host CPU.
Source
Thrown at packages/server/src/jsRunner/vm/isolated-vm.ts:181
const bsonPolyfills = loadBundle(BundleType.BSON_POLYFILLS)
const script = this.isolate.compileScriptSync(
`${bsonPolyfills};${bsonSource}`
)
script.runSync(this.vm, { timeout: this.invocationTimeout, release: false })
new Promise(() => {
script.release()
})
return this
}
execute(code: string): any {
if (this.isolateAccumulatedTimeout) {
const cpuMs = Number(this.isolate.cpuTime) / 1e6
if (cpuMs > this.isolateAccumulatedTimeout) {
throw new JsRequestTimeoutError(
`CPU time limit exceeded (${cpuMs}ms > ${this.isolateAccumulatedTimeout}ms)`
)
}
}
code = `
try {
results = {}
results['${this.runResultKey}']=${this.codeWrapper(code)}
} catch (e) {
results['${this.runErrorKey}']=e
}
`
const script = this.isolate.compileScriptSync(code)
script.runSync(this.vm, { timeout: this.invocationTimeout, release: false })
new Promise(() => {View on GitHub (pinned to a81a902e9a)
Solutions
- Increase the isolateAccumulatedTimeout / CPU limit configuration to a value suited to your workloads.
- Recycle the isolate (create a fresh one) once its CPU budget is consumed instead of reusing it.
- Profile and optimize the user JS executing on the isolate to reduce CPU consumption.
- Distribute load across multiple isolates so no single one exhausts its budget.
Example fix
// before: one shared isolate reused until budget exhausted const runner = getSharedIsolate() runner.execute(code) // JsRequestTimeoutError after budget used // after: recycle isolate when CPU budget is spent if (runner.cpuTimeMs() > runner.limitMs()) runner = createIsolate() runner.execute(code)
Defensive patterns
Strategy: try-catch
Validate before calling
// Check remaining CPU budget before executing
const cpuMs = Number(isolate.cpuTime) / 1e6
if (cpuMs > isolateAccumulatedTimeout) {
isolate = createNewIsolate() // recycle before execute()
} Type guard
function isCpuTimeout(err: unknown): err is Error & { code: string } {
return err instanceof Error && (err as { code?: string }).code === "JS_REQUEST_TIMEOUT_ERROR"
} Try / catch
try {
const result = isolateVm.execute(code)
} catch (err) {
if (isCpuTimeout(err)) {
recycleIsolate() // fresh isolate with a clean CPU budget, then retry once
} else { throw err }
} Prevention
- Recycle isolates proactively instead of reusing them indefinitely
- Set isolateAccumulatedTimeout to match realistic per-workload CPU needs
- Optimize hot user JS to reduce cumulative CPU consumption
- Monitor isolate cpuTime metrics and alert before the budget is exhausted
When it happens
Trigger: Calling execute() on an isolate whose accumulated CPU time already exceeds isolateAccumulatedTimeout — e.g. many prior executions on the same isolate consumed the CPU budget, or the configured limit is very low so even modest scripts trip it.
Common situations: Long-lived isolate reused across many requests slowly exhausting its CPU budget; too-low timeout config in production; a single expensive script burning most of the budget so subsequent cheap calls fail; CPU throttling in containers inflating measured CPU time.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/94d7bc3efd0c029a.
Report an issue: GitHub.