apache/beam · error · ValueError

Ambiguous expression type (perhaps missing quoting?)

Error message

Ambiguous expression type (perhaps missing quoting?): {expr_dict}

What it means

Beam YAML's validate_generic_expression checks that a mapping field's custom logic is a plain string expression or a dict like {expression: ...}. This ValueError fires when expr_dict is not a dict at all — e.g. a string, list, or scalar was passed where a language-specifying map was required. The 'perhaps missing quoting?' hint means a bare string that looks like an expression may have been YAML-parsed into a non-dict type.

Solutions

  1. Quote the value or structure it as a single-key map, e.g. `expression: "col + 1"` wrapped correctly so YAML yields a dict with an 'expression' key.
  2. Check YAML indentation — a mis-indented entry can parse as a list or scalar instead of a mapping.
  3. In programmatic use, verify the argument is a dict before calling: isinstance(expr_dict, dict).
  4. Use a language-tagged form like {expression: ..., language: python} if generic expressions are too ambiguous.

Example fix

# before (parses ambiguously / as string)
mapping:
  output: col1 + : col2
# after
custom:
  language: python
  expression: "col1 + col2"
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(cfg, dict) or list(cfg.keys()) != ['expression']:
    raise ValueError('mapping custom logic must be a single-key {expression: ...} map')

Type guard

def is_expr_map(v): return isinstance(v, dict) and 'expression' in v

Prevention

When it happens

Trigger: Calling validate_generic_expression (via validate_generic_expressions) with a mapping entry whose value is not a dict — e.g. a YAML inline mapping parsed as a string due to unquoted special characters, or a list/tuple passed in.

Common situations: YAML config where the expression value contains colons or braces so the parser produces a string or nested structure instead of a single-key map; users writing `expression: row.a + row.b` instead of `{expression: ...}` with a language key; programmatic API misuse passing a raw string.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

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

def is_literal(expr: str) -> bool:
  # Some languages have limited integer literal ranges.
  if re.fullmatch(r'-?\d+?', expr) and -1 << 31 < int(expr) < 1 << 31:
    return True
  elif re.fullmatch(r'-?\d+\.\d*', expr):
    return True
  elif re.fullmatch(r'"[^\\"]*"', expr):
    return True
  else:
    return False


def validate_generic_expression(
    expr_dict: dict,
    input_fields: Collection[str],
    allow_cmp: bool,
    error_field: str) -> None:
  if not isinstance(expr_dict, dict):
    raise ValueError(
        f"Ambiguous expression type (perhaps missing quoting?): {expr_dict}")
  if len(expr_dict) != 1 or 'expression' not in expr_dict:
    raise ValueError(
        "Missing language specification. "
        "Must specify a language when using a map with custom logic for %s" %
        error_field)
  expr = str(expr_dict['expression'])

  def is_atomic(expr: str):
    return is_literal(expr) or expr in input_fields

  if is_atomic(expr):
    return

  if allow_cmp:
    maybe_cmp = re.fullmatch('(.*)([<>=!]+)(.*)', expr)
    if maybe_cmp:
      left, cmp, right = maybe_cmp.groups()

View on GitHub (pinned to 12126d8942)