apache/beam · error · ValueError

Unknown operation action

Error message

Unknown operation action: %s

What it means

In the Spanner write batch processing DoFn, each WriteMutation's operation kind is dispatched to the corresponding batch method (insert/update/insert_or_update/replace/delete). If a mutation carries an unrecognized operation value, the library raises this ValueError because no batch method exists for it.

Solutions

  1. Create mutations only via WriteMutation.insert/update/insert_or_update/replace/delete factory methods.
  2. Do not mutate the _operation attribute directly.
  3. Ensure the Beam SDK version used to serialize mutations matches the worker's SDK version (check beam_version in pipeline options).

Example fix

# before
m = WriteMutation.__new__(WriteMutation); m._operation = 'upsert'
# after
m = WriteMutation.insert_or_update(table, rows)
Defensive patterns

Strategy: try-catch

Validate before calling

def valid_mutation(m):
    return getattr(m, 'operation', None) in {
        WriteMutation._OPERATION_INSERT, WriteMutation._OPERATION_UPDATE,
        WriteMutation._OPERATION_INSERT_OR_UPDATE, WriteMutation._OPERATION_REPLACE,
        WriteMutation._OPERATION_DELETE}

Try / catch

try:
    output = pcoll | spannerwrite
except ValueError as e:
    if 'Unknown operation action' in str(e):
        logging.error('Corrupt WriteMutation operation in stream: %s', e)
    raise

Prevention

When it happens

Trigger: A WriteMutation object with a corrupted or hand-crafted _operation value (e.g. constructed by bypassing the class factory methods and setting operation directly), or a custom subclass introducing a new operation string not handled in process().

Common situations: Deserializing WriteMutation objects across Beam worker versions where operation constants differ; monkey-patching or pickling mutations between SDK versions.

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/b020983d861bf145. Report an issue: GitHub.

Appendix: source

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

    self.batches.inc()
    try:
      with self._db_instance.batch() as b:
        for m in element:
          table_id = m.kwargs['table']
          self._register_table_metric(table_id)

          if m.operation == WriteMutation._OPERATION_DELETE:
            batch_func = b.delete
          elif m.operation == WriteMutation._OPERATION_REPLACE:
            batch_func = b.replace
          elif m.operation == WriteMutation._OPERATION_INSERT_OR_UPDATE:
            batch_func = b.insert_or_update
          elif m.operation == WriteMutation._OPERATION_INSERT:
            batch_func = b.insert
          elif m.operation == WriteMutation._OPERATION_UPDATE:
            batch_func = b.update
          else:
            raise ValueError("Unknown operation action: %s" % m.operation)
          batch_func(**m.kwargs)
    except (ClientError, GoogleAPICallError) as e:
      for service_metric in self.service_metrics.values():
        service_metric.call(str(e.code.value))
      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):

View on GitHub (pinned to 12126d8942)