apache/beam · error · TypeError

Field expression %r at

Error message

Field expression %r at %s must be a callable or a string.

What it means

Raised by apache_beam.transforms.core._expr_to_callable, a helper used by GroupBy to turn key/field expressions into callables. A field expression must either be a string naming an attribute of each element, or a callable taking the element and returning the key value. Anything else (int, dict, None, etc.) cannot be interpreted, so a TypeError is raised naming the offending expression and its position.

Solutions

  1. Pass attribute names as strings: beam.GroupBy('field_name') instead of beam.GroupBy(field_name).
  2. If the key is computed, pass a lambda/function: beam.GroupBy(lambda x: x.field).
  3. For multiple fields, pass multiple strings/callables: beam.GroupBy('a', 'b').
  4. Validate your expression list before constructing: all(isinstance(e, (str,)) or callable(e) for e in exprs).

Example fix

// before
import beam
result = pc | beam.GroupBy(field_id)  # field_id = 7
// after
result = pc | beam.GroupBy('field_id')
Defensive patterns

Strategy: type-guard

Validate before calling

def check_exprs(exprs):
    assert all(isinstance(e, str) or callable(e) for e in exprs), 'GroupBy expressions must be str or callable'

Type guard

def is_field_expr(e):
    return isinstance(e, str) or callable(e)

Prevention

When it happens

Trigger: Passing a non-string, non-callable to GroupBy's field expressions, e.g. beam.GroupBy(42), GroupBy(None), GroupBy({'a': 1}), or a list of expressions where one element is not a str/callable.

Common situations: Typos such as GroupBy(a, b) passing raw variable names (values like 42) instead of strings 'a'; refactoring code that changed a lambda into a value; building expressions dynamically from config where a numeric field index is passed instead of a field name string.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at sdks/python/apache_beam/transforms/core.py:3570

    return common_urns.primitives.GROUP_BY_KEY.urn, None

  @staticmethod
  @PTransform.register_urn(common_urns.primitives.GROUP_BY_KEY.urn, None)
  def from_runner_api_parameter(
      unused_ptransform, unused_payload, unused_context):
    return GroupByKey()

  def runner_api_requires_keyed_input(self):
    return True


def _expr_to_callable(expr, pos):
  if isinstance(expr, str):
    return lambda x: getattr(x, expr)
  elif callable(expr):
    return expr
  else:
    raise TypeError(
        'Field expression %r at %s must be a callable or a string.' %
        (expr, pos))


class GroupBy(PTransform):
  """Groups a PCollection by one or more expressions, used to derive the key.

  `GroupBy(expr)` is roughly equivalent to

      beam.Map(lambda v: (expr(v), v)) | beam.GroupByKey()

  but provides several conveniences, e.g.

      * Several arguments may be provided, as positional or keyword arguments,
        resulting in a tuple-like key. For example `GroupBy(a=expr1, b=expr2)`
        groups by a key with attributes `a` and `b` computed by applying
        `expr1` and `expr2` to each element.

View on GitHub (pinned to 12126d8942)