apache/beam · error · ValueError

Main output tag %r must be different from side output tags %

Error message

Main output tag %r must be different from side output tags %r.

What it means

When a ParDo declares multiple outputs, each output is identified by a tag. The main output tag and side output tags must be distinct namespaces; Beam raises this ValueError at transform validation time if the requested main tag collides with one of the side output tags.

Source

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

        be used for the main output (which will not have a tag associated with
        it).

    Returns:
      ~apache_beam.pvalue.DoOutputsTuple: An object of type
      :class:`~apache_beam.pvalue.DoOutputsTuple` that bundles together all
      the outputs of a :class:`ParDo` transform and allows accessing the
      individual :class:`~apache_beam.pvalue.PCollection` s for each output
      using an ``object.tag`` syntax.

    Raises:
      TypeError: if the **self** object is not a
        :class:`~apache_beam.pvalue.PCollection` that is the result of a
        :class:`ParDo` transform.
      ValueError: if **main_kw** contains any key other than
        ``'main'``.
    """
    if main in tags:
      raise ValueError(
          'Main output tag %r must be different from side output tags %r.' %
          (main, tags))
    type_hints = self.get_type_hints()
    declared_tags = set(type_hints.tagged_output_types().keys())
    requested_tags = set(tags)

    unknown = requested_tags - declared_tags
    if unknown and declared_tags:  # Only warn if type hints exist
      logging.warning(
          "Tags %s requested in with_outputs() but not declared "
          "in type hints. Declared tags: %s",
          unknown,
          declared_tags)
    return _MultiParDo(self, tags, main, allow_unknown_tags)

  def _do_fn_info(self):
    return DoFnInfo.create(self.fn, self.args, self.kwargs)

View on GitHub (pinned to 12126d8942)

Solutions

  1. Rename the colliding side output tag so it differs from the main tag.
  2. Explicitly choose a distinct main tag, e.g. with_outputs('side1', main='primary').
  3. Deduplicate/validate the tag list programmatically before calling with_outputs (set difference between tags and main).

Example fix

// before
pardo.with_outputs('main', 'main', 'other')
// after
pardo.with_outputs('main', 'side_main', 'other')
Defensive patterns

Strategy: validation

Validate before calling

tags = ['side1', 'side2']
main = 'main'
assert main not in tags, f'main tag {main!r} collides with side tags {tags}'

Type guard

def tags_are_disjoint(main, tags):
    return main not in tags

Try / catch

try:
    pardo = pardo.with_outputs(*tags, main=main)
except ValueError as e:
    logger.error('Output tag collision: %s', e)
    raise

Prevention

When it happens

Trigger: Calling pardo.with_outputs('main', *side_tags) or with_outputs(tag, main='tag') where the main tag string is also present in the side output tags tuple.

Common situations: Copy-paste of tag strings; defaulting main='main' while also passing 'main' as a side tag; dynamically built tag lists that accidentally include the main tag.

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/9c6eccaa81b3f4f6. Report an issue: GitHub.