apache/beam · error · TypeError

Chain at {identify_object(spec)} missing transforms property

Error message

Chain at {identify_object(spec)} missing transforms property.

What it means

A 'chain' transform in Beam YAML is sugar for a composite whose transforms pass outputs to inputs implicitly. chain_as_composite raises this TypeError when the chain spec lacks the required 'transforms' property, since there is nothing to chain.

Source

Thrown at sdks/python/apache_beam/yaml/yaml_transform.py:926

            scope.root) | scope.unique_name(spec, None) >> transform


def expand_chain_transform(spec, scope):
  return expand_composite_transform(chain_as_composite(spec), scope)


def chain_as_composite(spec):
  def is_not_output_of_last_transform(new_transforms, value):
    return (
        ('name' in new_transforms[-1] and
         value != new_transforms[-1]['name']) or
        ('type' in new_transforms[-1] and value != new_transforms[-1]['type']))

  # A chain is simply a composite transform where all inputs and outputs
  # are implicit.
  spec = normalize_source_sink(spec)
  if 'transforms' not in spec:
    raise TypeError(
        f"Chain at {identify_object(spec)} missing transforms property.")
  has_explicit_outputs = 'output' in spec
  composite_spec = dict(normalize_inputs_outputs(tag_explicit_inputs(spec)))
  new_transforms = []
  for ix, transform in enumerate(composite_spec['transforms']):
    transform = dict(transform)
    if any(io in transform for io in ('input', 'output')):
      if (ix == 0 and 'input' in transform and 'output' not in transform and
          is_explicitly_empty(transform['input'])):
        # This is OK as source clause sets an explicitly empty input.
        pass
      else:
        raise ValueError(
            f'Transform {identify_object(transform)} is part of a chain. '
            'Cannot define explicit inputs on chain pipeline')
    if ix == 0:
      if is_explicitly_empty(transform.get('input', None)):
        pass

View on GitHub (pinned to 12126d8942)

Solutions

  1. Add a 'transforms' list with at least one transform to the chain spec.
  2. Fix YAML indentation so 'transforms:' is nested inside the chain transform block.
  3. If the transform is not actually a chain, change its 'type' to 'composite' or a leaf type.
  4. Validate the spec against the Beam YAML schema before running.

Example fix

// before
- name: MyPipeline
  type: chain
  input: source
// after
- name: MyPipeline
  type: chain
  input: source
  transforms:
    - type: MapToFields
      config:
        id: element.id
Defensive patterns

Strategy: validation

Validate before calling

def check_chain_spec(spec):
    if spec.get('type') == 'chain' and 'transforms' not in spec:
        raise ValueError('Chain spec must include a transforms list')

Type guard

def is_complete_chain(spec) -> bool:
    return isinstance(spec, dict) and spec.get('type') == 'chain' and isinstance(spec.get('transforms'), list)

Try / catch

try:
    expand_transform(spec, scope)
except TypeError as e:
    if 'missing transforms property' in str(e):
        print('Add transforms list to the chain spec')
    else:
        raise

Prevention

When it happens

Trigger: A spec like {type: chain, name: MyChain, input: ...} with no 'transforms:' list — typically from YAML indentation issues or building chain specs programmatically without the transforms key.

Common situations: YAML where 'transforms:' is mis-indented so it lands outside the chain mapping; hand-editing a pipeline and deleting the transforms list; generating specs in tooling that omits transforms for empty chains.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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