apache/beam · error · ValueError

Tag '%s' is neither the main tag '%s' nor any of the tags %s

Error message

Tag '%s' is neither the main tag '%s' nor any of the tags %s

What it means

ValueError raised by DoOutputsTuple.__getitem__ when indexing a multi-output PCollection tuple with a tag that is neither the main tag nor one of the declared side-output tags, and unknown tags are not allowed. It protects against typos in side-output tag access.

Source

Thrown at sdks/python/apache_beam/pvalue.py:293

  def __getattr__(self, tag: str) -> PCollection:
    # Special methods which may be accessed before the object is
    # fully constructed (e.g. in unpickling).
    if tag[:2] == tag[-2:] == '__':
      return object.__getattr__(self, tag)  # type: ignore
    return self[tag]

  def __getitem__(self, tag: Union[int, str, None]) -> PCollection:
    # Accept int tags so that we can look at Partition tags with the
    # same ints that we used in the partition function.
    # TODO(gildea): Consider requiring string-based tags everywhere.
    # This will require a partition function that does not return ints.
    if isinstance(tag, int):
      tag = str(tag)
    if tag == self._main_tag:
      tag = None
    elif self._tags and tag not in self._tags and not self._allow_unknown_tags:
      raise ValueError(
          "Tag '%s' is neither the main tag '%s' "
          "nor any of the tags %s" % (tag, self._main_tag, self._tags))
    # Check if we accessed this tag before.
    if tag in self._pcolls:
      return self._pcolls[tag]

    assert self.producer is not None
    if tag is not None:
      self._transform.output_tags.add(tag)
      is_bounded = all(i.is_bounded for i in self.producer.main_inputs.values())
      pcoll = PCollection(
          self._pipeline,
          tag=tag,
          element_type=self._tagged_output_types.get(tag, typehints.Any),
          is_bounded=is_bounded)
      # Transfer the producer from the DoOutputsTuple to the resulting
      # PCollection.
      pcoll.producer = self.producer.parts[0]

View on GitHub (pinned to 12126d8942)

Solutions

  1. Use one of the exact tags declared in DoFn.with_outputs(...) / emitted with beam.tag_output
  2. Check available tags by inspecting the DoFn's output tags before indexing
  3. Declare with_outputs('*', *extra_tags) or allow_unknown_tags=True if dynamic tags are intended

Example fix

// before
main, bad = results['main'], results['badd']
// after
main, bad = results[None], results['bad']
Defensive patterns

Strategy: validation

Validate before calling

declared = set(dofn.with_outputs_tags) | {None}
assert tag in declared, f'{tag} not in {declared}'

Try / catch

try:
    bad = results['bad']
except ValueError as e:
    logging.error('Bad side-output tag: %s', e)
    bad = results[None]

Prevention

When it happens

Trigger: Accessing results['typo_tag'] on the output of a DoFn using beam.tag_output(...) with tags like 'errors'; using an int not emitted via with_outputs declared tags; indexing a tag removed after refactoring.

Common situations: Renaming side-output tags in a DoFn without updating downstream accesses; confusing main output (tag None/'') with declared tags.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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