Budibase/budibase · error · UserScriptError

USER_SCRIPT_ERROR

USER_SCRIPT_ERROR

Error message

error while running user-supplied JavaScript: ${userScriptError.toString()}

What it means

The isolated-vm JS runner wraps user-supplied JavaScript in a try/catch inside the V8 isolate. Any error the user's script throws (or which comes from the script's own logic/callbacks) is captured and re-thrown on the host side as a UserScriptError after execution, distinguishing user mistakes from host infrastructure failures.

Source

Thrown at packages/server/src/jsRunner/vm/isolated-vm.ts:206

      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(() => {
      script.release()
    })

    // We can't rely on the script run result as it will not work for non-transferable values
    const result = this.getFromContext(this.resultKey)
    if (result[this.runErrorKey]) {
      throw new UserScriptError(result[this.runErrorKey])
    }
    return result[this.runResultKey]
  }

  close(): void {
    this.vm.release()
    this.isolate.dispose()
  }

  private registerCallbacks(functions: Record<string, any>) {
    const libId = crypto.randomUUID().replace(/-/g, "")

    const x: Record<string, string> = {}
    for (const [funcName, func] of Object.entries(functions)) {
      const key = `f${libId}${funcName}cb`
      x[funcName] = key

      this.addToContext({

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Read the embedded userScriptError message - it is the original error from inside the sandbox; fix the user JS accordingly.
  2. Verify all referenced variables/fields exist and are defined before the script runs (null-check row/data inputs).
  3. Test the snippet in a plain Node REPL with mocked inputs to reproduce the error outside the isolate.
  4. If a registered callback throws, fix the callback implementation on the host side rather than the script.

Example fix

// before
return data.rows[0].value * 2
// after
return data.rows && data.rows[0] ? data.rows[0].value * 2 : 0
Defensive patterns

Strategy: try-catch

Validate before calling

if (typeof userCode !== "string" || !userCode.trim()) throw new Error("Empty script")

Type guard

const isUserScriptError = (e: unknown): e is UserScriptError => e instanceof UserScriptError

Try / catch

try {
  const result = runner.execute(code)
} catch (e) {
  if (e instanceof UserScriptError) {
    // surface e.message to the user as a script problem, not a server fault
  } else {
    throw e
  }
}

Prevention

When it happens

Trigger: Calling execute(code) where the user JavaScript throws at runtime: undefined variable access, type errors, a registered callback function rejects/throws, or bson conversion fails. The isolate itself ran fine; the script errored.

Common situations: Builders write JS bindings in automations/queries that reference missing row fields, call helper functions with wrong arguments, or use APIs not available in the sandbox. CPU-time limit breaches throw a different error (JsRequestTimeoutError), not this one.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/af5b644d5c78c193. Report an issue: GitHub.