apache/beam · error · ValueError

Invalid object type: . Object must be an instance of…

Error message

Invalid object type: %s. Object must be an instance of MutationGroup or WriteMutations

What it means

SpannerIO's Write DoFn (process) accepts only MutationGroup instances or _Mutator (WriteMutation) objects to write to Spanner. Any other element type on the PCollection entering SpannerWrite triggers this ValueError.

Solutions

  1. Wrap each element: beam.Map(lambda row: WriteMutation.insert(table, [row])) before SpannerWrite.
  2. Group several mutations per element with MutationGroup([...]).
  3. If piping a PCollection of MutationGroup already, verify upstream transforms do not unpack them back to raw rows.

Example fix

# before
rows | 'write' >> spannerio.SpannerWrite(project, instance, database)
# after
rows | 'to_mut' >> beam.Map(lambda r: WriteMutation.insert('tbl', [r])) | 'write' >> spannerio.SpannerWrite(project, instance, database)
Defensive patterns

Strategy: type-guard

Validate before calling

def validate_mutation_elements(pcoll):
    from apache_beam.io.gcp.experimental.spannerio import MutationGroup
    def check(el):
        if not isinstance(el, (MutationGroup,)) and not hasattr(el, 'operation'):
            raise TypeError('Element %r must be MutationGroup or WriteMutation' % el)
        return el
    return pcoll | beam.Map(check)

Type guard

def is_spanner_writable(el):
    from apache_beam.io.gcp.experimental.spannerio import MutationGroup
    from apache_beam.io.gcp.experimental.spannerio import _Mutator
    return isinstance(el, (MutationGroup, _Mutator))

Prevention

When it happens

Trigger: Piping a PCollection of dicts, rows, or tuples directly into spannerio.SpannerWrite / WriteToSpanner without wrapping each element in WriteMutation or MutationGroup.

Common situations: Coming from other Beam sinks where you pipe plain records directly (e.g. like WriteToBigQuery with dicts) and expecting SpannerWrite to accept raw rows; missing the WriteMutation() wrapping step.

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


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

Appendix: source

Thrown at sdks/python/apache_beam/io/gcp/experimental/spannerio.py:1284

      raise
    else:
      for service_metric in self.service_metrics.values():
        service_metric.call('ok')


@with_input_types(typing.Union[MutationGroup, _Mutator])
@with_output_types(MutationGroup)
class _MakeMutationGroupsFn(DoFn):
  """
  Make Mutation group object if the element is the instance of _Mutator.
  """
  def process(self, element):
    if isinstance(element, MutationGroup):
      yield element
    elif isinstance(element, _Mutator):
      yield MutationGroup([element])
    else:
      raise ValueError(
          "Invalid object type: %s. Object must be an instance of "
          "MutationGroup or WriteMutations" % str(element))


class _WriteGroup(PTransform):
  def __init__(self, max_batch_size_bytes, max_number_rows, max_number_cells):
    self._max_batch_size_bytes = max_batch_size_bytes
    self._max_number_rows = max_number_rows
    self._max_number_cells = max_number_cells

  def expand(self, pcoll):
    filter_batchable_mutations = (
        pcoll
        | 'Making mutation groups' >> ParDo(_MakeMutationGroupsFn())
        | 'Filtering Batchable Mutations' >> ParDo(
            _BatchableFilterFn(
                max_batch_size_bytes=self._max_batch_size_bytes,
                max_number_rows=self._max_number_rows,

View on GitHub (pinned to 12126d8942)