{"record":{"id":"80242422f56395bc","repo":"apache/beam","slug":"chain-at-identify-object-spec-missing-transforms-property","errorCode":null,"errorMessage":"Chain at {identify_object(spec)} missing transforms property.","messagePattern":"Chain at (.+?) missing transforms property\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/yaml/yaml_transform.py","lineNumber":926,"sourceCode":"            scope.root) | scope.unique_name(spec, None) >> transform\n\n\ndef expand_chain_transform(spec, scope):\n  return expand_composite_transform(chain_as_composite(spec), scope)\n\n\ndef chain_as_composite(spec):\n  def is_not_output_of_last_transform(new_transforms, value):\n    return (\n        ('name' in new_transforms[-1] and\n         value != new_transforms[-1]['name']) or\n        ('type' in new_transforms[-1] and value != new_transforms[-1]['type']))\n\n  # A chain is simply a composite transform where all inputs and outputs\n  # are implicit.\n  spec = normalize_source_sink(spec)\n  if 'transforms' not in spec:\n    raise TypeError(\n        f\"Chain at {identify_object(spec)} missing transforms property.\")\n  has_explicit_outputs = 'output' in spec\n  composite_spec = dict(normalize_inputs_outputs(tag_explicit_inputs(spec)))\n  new_transforms = []\n  for ix, transform in enumerate(composite_spec['transforms']):\n    transform = dict(transform)\n    if any(io in transform for io in ('input', 'output')):\n      if (ix == 0 and 'input' in transform and 'output' not in transform and\n          is_explicitly_empty(transform['input'])):\n        # This is OK as source clause sets an explicitly empty input.\n        pass\n      else:\n        raise ValueError(\n            f'Transform {identify_object(transform)} is part of a chain. '\n            'Cannot define explicit inputs on chain pipeline')\n    if ix == 0:\n      if is_explicitly_empty(transform.get('input', None)):\n        pass","sourceCodeStart":908,"sourceCodeEnd":944,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/yaml/yaml_transform.py#L908-L944","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Add a 'transforms' list with at least one transform to the chain spec.","Fix YAML indentation so 'transforms:' is nested inside the chain transform block.","If the transform is not actually a chain, change its 'type' to 'composite' or a leaf type.","Validate the spec against the Beam YAML schema before running."],"exampleFix":"// before\n- name: MyPipeline\n  type: chain\n  input: source\n// after\n- name: MyPipeline\n  type: chain\n  input: source\n  transforms:\n    - type: MapToFields\n      config:\n        id: element.id","handlingStrategy":"validation","validationCode":"def check_chain_spec(spec):\n    if spec.get('type') == 'chain' and 'transforms' not in spec:\n        raise ValueError('Chain spec must include a transforms list')","typeGuard":"def is_complete_chain(spec) -> bool:\n    return isinstance(spec, dict) and spec.get('type') == 'chain' and isinstance(spec.get('transforms'), list)","tryCatchPattern":"try:\n    expand_transform(spec, scope)\nexcept TypeError as e:\n    if 'missing transforms property' in str(e):\n        print('Add transforms list to the chain spec')\n    else:\n        raise","preventionTips":["Always include 'transforms:' in chain specs, even for single-step chains.","Check YAML indentation so transforms nests inside the chain block.","Use composite instead of chain when explicit io wiring is needed."],"tags":["python","apache-beam","yaml","config"],"backgroundTag":"missing-required-config-field","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}