{"record":{"id":"109ed06125ff5781","repo":"Budibase/budibase","slug":"js-timeout-error","errorCode":"JS_TIMEOUT_ERROR","errorMessage":"Timed out while executing JS","messagePattern":"Timed out while executing JS","errorType":"exception","errorClass":"JsTimeoutError","httpStatus":null,"severity":"error","filePath":"packages/server/src/jsRunner/index.ts","lineNumber":48,"sourceCode":"            .withHelpers()\n            .withBuffer()\n            .withSnippets(bbCtx?.snippets)\n\n        // Persist isolate in context so we can reuse it\n        if (bbCtx && !bbCtx.vm) {\n          bbCtx.vm = vm\n          bbCtx.cleanup = bbCtx.cleanup || []\n          bbCtx.cleanup.push(() => vm.close())\n        }\n\n        // Because we can't pass functions into an Isolate, we remove them from\n        // the passed context and rely on the withHelpers() method to add them\n        // back in.\n        const { helpers, snippets, ...rest } = ctx\n        return vm.withContext(rest, () => vm.execute(js))\n      } catch (error: any) {\n        if (error.message === \"Script execution timed out.\") {\n          throw new JsTimeoutError()\n        }\n        throw error\n      }\n    })\n  })\n\n  if (env.LOG_JS_ERRORS) {\n    setOnErrorLog((error: Error) => {\n      logging.logWarn(\n        `Error while executing js: ${JSON.stringify(serializeError(error))}`\n      )\n    })\n  }\n}\n","sourceCodeStart":30,"sourceCodeEnd":63,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/jsRunner/index.ts#L30-L63","documentation":"The JS runner executes user JavaScript inside a VM with an execution timeout. When the underlying VM aborts with 'Script execution timed out.', init converts it into a typed JsTimeoutError (code JS_TIMEOUT_ERROR) so callers can recognize the script ran too long and was terminated instead of crashing with a generic error.","triggerScenarios":"Executing a user-defined JS snippet (via the runner's init/execute path, e.g. triggered through publishAsyncEvent) whose script exceeds the configured VM execution timeout — typically infinite loops, unbounded recursion, or very heavy synchronous computation.","commonSituations":"Automation/JS bindings with a `while` loop that never terminates; accidentally calling the script recursively; transforming a huge dataset synchronously; regression after adding expensive per-row JS logic; timeout configured too low for legitimately heavy scripts.","solutions":["Review the executed JS for non-terminating loops or unbounded recursion and fix the termination condition.","Move heavy data processing out of JS bindings (e.g. into automations or pre-computed data).","Raise the JS runner timeout configuration if the script legitimately needs more time.","Break large synchronous work into smaller batches processed across multiple executions."],"exampleFix":"// before\nlet done = false\nwhile (!done) { /* never sets done */ }\n// after\nfor (let i = 0; i < rows.length; i++) {\n  if (matches(rows[i])) { result = rows[i]; break }\n}","handlingStrategy":"try-catch","validationCode":"// Static sanity check before running user JS\nfunction hasBoundedLoops(code: string): boolean {\n  return !/while\\s*\\(\\s*(true|1)\\s*\\)/.test(code)\n}","typeGuard":"function isJsTimeout(err: unknown): err is Error & { code: string } {\n  return err instanceof Error && (err as { code?: string }).code === \"JS_TIMEOUT_ERROR\"\n}","tryCatchPattern":"try {\n  const result = await jsRunner.init(context).execute(js)\n} catch (err) {\n  if (isJsTimeout(err)) {\n    // mark the binding as timed out, skip or surface a user-facing message\n  } else { throw err }\n}","preventionTips":["Review user JS for non-terminating loops and unbounded recursion","Avoid heavy synchronous computation in JS bindings","Set the VM execution timeout appropriately for expected workloads","Process large datasets in batches instead of one big script"],"tags":["javascript","vm","timeout","js-runner"],"backgroundTag":"script-execution-timeout","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}