apache/beam · error · ValueError
A sink must inherit iobase.Sink, iobase.NativeSink, or be a
Error message
A sink must inherit iobase.Sink, iobase.NativeSink, or be a PTransform. Received : %r
What it means
apache_beam.io.iobase.Write.expand validates that the sink passed to WriteToTransform is either an iobase.Sink, a NativeSink, or a PTransform. Any other object (a class instead of instance, a string, a connector config object) cannot be written to and raises ValueError. This guards the two supported write paths: custom Sink (wrapped in WriteImpl) and composite PTransform sinks.
Source
Thrown at sdks/python/apache_beam/io/iobase.py:1127
self.sink = sink
def display_data(self):
return {'sink': self.sink.__class__, 'sink_dd': self.sink}
def expand(self, pcoll):
# Importing locally to prevent circular dependencies.
from apache_beam.io.gcp.pubsub import _PubSubSink
if isinstance(self.sink, _PubSubSink):
# TODO(BEAM-27443): Remove the need for special casing here.
return pvalue.PDone(pcoll.pipeline)
elif isinstance(self.sink, Sink):
# A custom sink
return pcoll | WriteImpl(self.sink)
elif isinstance(self.sink, ptransform.PTransform):
# This allows "composite" sinks to be used like non-composite ones.
return pcoll | self.sink
else:
raise ValueError(
'A sink must inherit iobase.Sink, iobase.NativeSink, '
'or be a PTransform. Received : %r' % self.sink)
def to_runner_api_parameter(
self,
context: PipelineContext,
) -> tuple[str, Any]:
# TODO(BEAM-27443): Remove the need for special casing here.
# Importing locally to prevent circular dependencies.
from apache_beam.io.gcp.pubsub import _PubSubSink
if isinstance(self.sink, _PubSubSink):
payload = beam_runner_api_pb2.PubSubWritePayload(
topic=self.sink.full_topic,
id_attribute=self.sink.id_label,
timestamp_attribute=self.sink.timestamp_attribute)
return (common_urns.composites.PUBSUB_WRITE.urn, payload)
else:
return super().to_runner_api_parameter(context)View on GitHub (pinned to 12126d8942)
Solutions
- Instantiate the sink: pass MySink(...) (an instance) rather than MySink.
- Ensure the sink class inherits from apache_beam.io.iobase.Sink (or NativeSink) and implements write/build_writer.
- If the sink is a composite write, make it a PTransform subclass so it is accepted directly.
- Prefer the connector's public write transform (e.g. WriteToText, WriteToBigQuery) instead of building WriteToTransform manually.
Example fix
# before
result | WriteToTransform(WriteToText) # class passed, not instance
# after
result | WriteToTransform(WriteToText('/tmp/out')) # sink instance Defensive patterns
Strategy: type-guard
Validate before calling
from apache_beam.io import iobase assert isinstance(sink, (iobase.Sink, iobase.NativeSink)) or isinstance(sink, beam.transforms.ptransform.PTransform)
Type guard
def is_valid_sink(sink) -> bool:
from apache_beam.io import iobase
from apache_beam.transforms import ptransform
return isinstance(sink, (iobase.Sink, iobase.NativeSink, ptransform.PTransform)) Try / catch
try:
expanded = WriteToTransform(sink).expand(pcoll)
except ValueError as e:
if 'A sink must inherit' in str(e): log.error('Pass a Sink/PTransform instance, got %r', sink) Prevention
- Always pass sink instances, never classes
- Prefer built-in write transforms over WriteToTransform
- Verify custom sinks inherit iobase.Sink in unit tests
When it happens
Trigger: Calling WriteToTransform(sink).expand(pcoll) where sink is not an instance of iobase.Sink, iobase.NativeSink, or ptransform.PTransform - e.g. passing the sink class instead of an instance, or passing a connector-specific config/options object instead of the sink itself.
Common situations: Writing ReadAllResults with a hand-built WriteToTransform; copying code where the sink class name was passed rather than an instance; mixing up a custom IO's config object with its Sink implementation; typos in constructor calls.
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
- compression_type must be CompressionType object but was %s
- %s: file_pattern must be of type string or ValueProvider; go
- compression_type must be CompressionType object but was %s
- compression_type must be CompressionType object but was %s
- Encountered an Atomic type that is not currently supported b
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/fb2925bccb8da780.
Report an issue: GitHub.