{"record":{"id":"8dceda54aa718074","repo":"apache/beam","slug":"invalid-object-type-s-object-must-be-an-instance-of","errorCode":null,"errorMessage":"Invalid object type: %s. Object must be an instance of MutationGroup or WriteMutations","messagePattern":"Invalid object type: (.+?)\\. Object must be an instance of MutationGroup or WriteMutations","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/io/gcp/experimental/spannerio.py","lineNumber":1284,"sourceCode":"      raise\n    else:\n      for service_metric in self.service_metrics.values():\n        service_metric.call('ok')\n\n\n@with_input_types(typing.Union[MutationGroup, _Mutator])\n@with_output_types(MutationGroup)\nclass _MakeMutationGroupsFn(DoFn):\n  \"\"\"\n  Make Mutation group object if the element is the instance of _Mutator.\n  \"\"\"\n  def process(self, element):\n    if isinstance(element, MutationGroup):\n      yield element\n    elif isinstance(element, _Mutator):\n      yield MutationGroup([element])\n    else:\n      raise ValueError(\n          \"Invalid object type: %s. Object must be an instance of \"\n          \"MutationGroup or WriteMutations\" % str(element))\n\n\nclass _WriteGroup(PTransform):\n  def __init__(self, max_batch_size_bytes, max_number_rows, max_number_cells):\n    self._max_batch_size_bytes = max_batch_size_bytes\n    self._max_number_rows = max_number_rows\n    self._max_number_cells = max_number_cells\n\n  def expand(self, pcoll):\n    filter_batchable_mutations = (\n        pcoll\n        | 'Making mutation groups' >> ParDo(_MakeMutationGroupsFn())\n        | 'Filtering Batchable Mutations' >> ParDo(\n            _BatchableFilterFn(\n                max_batch_size_bytes=self._max_batch_size_bytes,\n                max_number_rows=self._max_number_rows,","sourceCodeStart":1266,"sourceCodeEnd":1302,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/io/gcp/experimental/spannerio.py#L1266-L1302","documentation":"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.","triggerScenarios":"Piping a PCollection of dicts, rows, or tuples directly into spannerio.SpannerWrite / WriteToSpanner without wrapping each element in WriteMutation or MutationGroup.","commonSituations":"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.","solutions":["Wrap each element: beam.Map(lambda row: WriteMutation.insert(table, [row])) before SpannerWrite.","Group several mutations per element with MutationGroup([...]).","If piping a PCollection of MutationGroup already, verify upstream transforms do not unpack them back to raw rows."],"exampleFix":"# before\nrows | 'write' >> spannerio.SpannerWrite(project, instance, database)\n# after\nrows | 'to_mut' >> beam.Map(lambda r: WriteMutation.insert('tbl', [r])) | 'write' >> spannerio.SpannerWrite(project, instance, database)","handlingStrategy":"type-guard","validationCode":"def validate_mutation_elements(pcoll):\n    from apache_beam.io.gcp.experimental.spannerio import MutationGroup\n    def check(el):\n        if not isinstance(el, (MutationGroup,)) and not hasattr(el, 'operation'):\n            raise TypeError('Element %r must be MutationGroup or WriteMutation' % el)\n        return el\n    return pcoll | beam.Map(check)","typeGuard":"def is_spanner_writable(el):\n    from apache_beam.io.gcp.experimental.spannerio import MutationGroup\n    from apache_beam.io.gcp.experimental.spannerio import _Mutator\n    return isinstance(el, (MutationGroup, _Mutator))","tryCatchPattern":null,"preventionTips":["Map records to WriteMutation before SpannerWrite","Use MutationGroup for multi-row elements","Check upstream transforms don't unwrap mutation wrappers"],"tags":["apache-beam","google-cloud-spanner","type-mismatch","valueerror"],"backgroundTag":"type-mismatch","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}