apache/beam · error · TypeError
In , tag is not a string
Error message
In %s, tag %s is not a string
What it means
When a DoFn emits a TaggedOutput (for multi-output ParDo via with_outputs), Beam's _handle_tagged_output unwraps it and validates the tag. The tag must be a str because it indexes the tagged_receivers dict for the declared output PCollection. A non-string tag means Beam cannot route the element to the correct output and raises TypeError.
Solutions
- Convert the tag to a string: `TaggedOutput(str(tag), value)`.
- Ensure the tag matches one of the outputs declared in `beam.DoFn(...).with_outputs('main', 'other')`.
- Add a validation/assertion in the DoFn before constructing the TaggedOutput.
Example fix
// before yield TaggedOutput(error_code, element) # error_code is an int // after yield TaggedOutput(str(error_code), element)
Defensive patterns
Strategy: validation
Validate before calling
assert isinstance(tag, str), f'TaggedOutput tag must be str, got {type(tag).__name__}' Type guard
def is_str_tag(tag):
return isinstance(tag, str) Try / catch
try:
out = pipeline_result.wait_until_finish()
except TypeError as e:
if 'tag' in str(e) and 'not a string' in str(e):
log.error('TaggedOutput tag must be a string matching with_outputs(): %s', e)
raise Prevention
- Define output tags as module-level string constants and reuse them in both TaggedOutput and with_outputs().
- Never construct tags from raw data (ints, enums) without str() conversion.
- Test multi-output DoFns with DirectRunner before submitting to a distributed runner.
When it happens
Trigger: Yielding `TaggedOutput(1, value)` or `TaggedOutput(('a','b'), value)` from a DoFn decorated to produce tagged outputs, where the tag passed to TaggedOutput is not a str.
Common situations: Passing an integer enum or tuple as a tag; forgetting that with_outputs() tags declared as strings must match exactly; dynamic tag construction using non-string values.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- A cluster_identifier should be Optional[Union[str…
- Cannot get a type descriptor for
- Cannot interpret as Duration.
- CombineGlobally can be used only with combineFn objects…
- database_config must be VectorDatabaseWriteConfig, got
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/50d383cbfb064c47.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/python/apache_beam/runners/common.py:1823
windowed_value.windows *= len(windowed_input_element.windows)
return windowed_value
elif isinstance(result, TimestampedValue):
assign_context = WindowFn.AssignContext(result.timestamp, result.value)
windowed_value = WindowedValue(
result.value, result.timestamp, self.window_fn.assign(assign_context))
if len(windowed_input_element.windows) != 1:
windowed_value.windows *= len(windowed_input_element.windows)
return windowed_value
else:
return windowed_input_element.with_value(result)
def _handle_tagged_output(self, result):
if isinstance(result, TaggedOutput):
tag = result.tag
if not isinstance(tag, str):
raise TypeError('In %s, tag %s is not a string' % (self, tag))
return tag, result.value
return None, result
def _write_value_to_tag(self, tag, windowed_value, watermark_estimator):
if watermark_estimator is not None:
watermark_estimator.observe_timestamp(windowed_value.timestamp)
if tag is None:
self.main_receivers.receive(windowed_value)
else:
self.tagged_receivers[tag].receive(windowed_value)
def _write_batch_to_tag(self, tag, windowed_batch, watermark_estimator):
if watermark_estimator is not None:
for timestamp in windowed_batch.timestamps:
watermark_estimator.observe_timestamp(timestamp)
if tag is None:View on GitHub (pinned to 12126d8942)