apache/beam · error · ValueError

Unexpected mutation

Error message

Unexpected mutation

What it means

WriteToBigTable's process() converts each mutation dict into a form suitable for the BigTable Write API and raises ValueError for mutation types it does not recognize. Only SetCell, DeleteFromColumn, DeleteFromFamily, and DeleteFromRow are accepted.

Source

Thrown at sdks/python/apache_beam/io/gcp/bigtableio.py:325

              "column_qualifier": mutation.delete_from_column.column_qualifier
          }
          time_range = mutation.delete_from_column.time_range
          if time_range.start_timestamp_micros:
            mutation_dict['start_timestamp_micros'] = struct.pack(
                '>q', time_range.start_timestamp_micros)
          if time_range.end_timestamp_micros:
            mutation_dict['end_timestamp_micros'] = struct.pack(
                '>q', time_range.end_timestamp_micros)
        elif mutation.__contains__("delete_from_family"):
          mutation_dict = {
              "type": b'DeleteFromFamily',
              "family_name": mutation.delete_from_family.family_name.encode(
                  'utf-8')
          }
        elif mutation.__contains__("delete_from_row"):
          mutation_dict = {"type": b'DeleteFromRow'}
        else:
          raise ValueError("Unexpected mutation")

        args["mutations"].append(mutation_dict)

      yield beam.Row(**args)


class ReadFromBigtable(PTransform):
  """Reads rows from Bigtable.

  Returns a PCollection of PartialRowData objects, each representing a
  Bigtable row. For more information about this row object, visit
  https://cloud.google.com/python/docs/reference/bigtable/latest/row#class-googlecloudbigtablerowpartialrowdatarowkey
  """
  URN = "beam:schematransform:org.apache.beam:bigtable_read:v1"

  def __init__(self, project_id, instance_id, table_id, expansion_service=None):
    """Initialize a ReadFromBigtable transform.

View on GitHub (pinned to 12126d8942)

Solutions

  1. Use beam.Row / the documented mutation dict keys exactly: set_cell, delete_from_column, delete_from_family, delete_from_row.
  2. Validate each mutation dict has one recognized key before writing to the sink.
  3. Prefer constructing mutations via the documented helpers rather than hand-built dicts.

Example fix

// before
row = {"delete_from_row": True, "unknown_op": 1}  # ValueError: Unexpected mutation

// after
row = {"delete_from_row": True}  # exactly one recognized mutation key
Defensive patterns

Strategy: validation

Validate before calling

VALID = {'set_cell', 'delete_from_column', 'delete_from_family', 'delete_from_row'}
for m in mutations:
    if not (set(m.keys()) & VALID):
        raise ValueError(f'mutation missing a recognized key: {m.keys()}')

Type guard

def is_valid_mutation(m):
    return isinstance(m, dict) and bool({'set_cell','delete_from_column','delete_from_family','delete_from_row'} & set(m.keys()))

Try / catch

try:
    result = pipeline | WriteToBigTable(project_id=..., instance_id=..., table_id=...)
except ValueError as e:
    if str(e) == 'Unexpected mutation':
        log.error('bad mutation dict in PCollection: check mutation keys')
    else:
        raise

Prevention

When it happens

Trigger: A PCollection element's mutation dict lacks any of the recognized keys (set_cell, delete_from_column, delete_from_family, delete_from_row), e.g. a typo like 'DeleteFromRow' vs expected key, or a mutation constructed manually with wrong keys.

Common situations: Building mutations by hand for WriteToBigTable with incorrect key names; passing raw protobuf Mutation objects instead of dicts; Beam version differences in accepted mutation dict key formats.

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