apache/beam · error · RuntimeError

Error evaluating javascript expression

Error message

Error evaluating javascript expression: {exn}

What it means

_JsFunctionWrapper.__call__ evaluates a JavaScript UDF via quickjs for each row. If the JS function raises or the row conversion fails, the exception is wrapped in a RuntimeError with the original exception chained ('Error evaluating javascript expression: {exn}').

Solutions

  1. Read the chained exception (exn) to find the JS-level error and line.
  2. Test the JS expression in a JS runtime/quickjs with a representative row.
  3. Add guards in JS for null/undefined fields before use.
  4. Verify output field names/types match the declared output schema.

Example fix

// before
function udf(row) {
  return {out: row.value + 1};  // throws if value undefined
}
// after
function udf(row) {
  return {out: (row.value == null ? 0 : Number(row.value)) + 1};
}
Defensive patterns

Strategy: try-catch

Validate before calling

new Function('row', js_body)({/* sample row */})  // dry-run the JS on a sample row

Try / catch

try:
    result = map_row(row)
except RuntimeError as e:
    logger.error('JS UDF failed for row %r: %s', row, e.__cause__)
    raise

Prevention

When it happens

Trigger: The JS expression/function throws at runtime for a given row — e.g. undefined property access, type coercion errors, returning a shape that doesn't match the expected output schema during dicts_to_rows conversion.

Common situations: Null/undefined handling mistakes in JS; field-name mismatches between the schema and the JS code; JS strict-mode type errors on unexpected input data.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/941d2a1b5752723a. Report an issue: GitHub.

Appendix: source

Thrown at sdks/python/apache_beam/yaml/yaml_mapping.py:227

        try:
          result = f(*[convert_arg(a) for a in args])
          if isinstance(result, quickjs.Object):
            result = json.loads(result.json())
          return result
        finally:
          if run_gc:
            context.gc()

      cache.functions[cache_key] = call_fn

    return cache.functions[cache_key]

  def __call__(self, row):
    fn = self._get_fn()
    try:
      return dicts_to_rows(fn(py_value_to_js_dict(row)))
    except Exception as exn:
      raise RuntimeError(
          f"Error evaluating javascript expression: {exn}") from exn


# TODO(yaml) Improve type inferencing for JS UDF's
def py_value_to_js_dict(py_value):
  if ((isinstance(py_value, tuple) and hasattr(py_value, '_asdict')) or
      isinstance(py_value, beam.Row)):
    py_value = py_value._asdict()
  if isinstance(py_value, dict):
    return {key: py_value_to_js_dict(value) for key, value in py_value.items()}
  elif isinstance(py_value, bytes):
    return py_value.decode('utf-8', errors='replace')
  elif isinstance(py_value, (datetime.datetime, datetime.date, datetime.time)):
    return {'__date__': True, 'value': py_value.isoformat()}
  elif isinstance(py_value, Decimal):
    return float(py_value)
  elif not isinstance(py_value, str) and isinstance(py_value, abc.Iterable):
    return [py_value_to_js_dict(value) for value in list(py_value)]

View on GitHub (pinned to 12126d8942)