apache/beam · error · ValueError

change_function must be 'CHANGES' or 'APPENDS', got '{change

Error message

change_function must be 'CHANGES' or 'APPENDS', got '{change_function}'

What it means

ReadBigQueryChangeHistory only supports the BigQuery change-history functions 'CHANGES' and 'APPENDS'. Any other change_function string is rejected in __init__ with a ValueError that echoes the invalid value, because the generated change-history query syntax depends on this enum.

Source

Thrown at sdks/python/apache_beam/io/gcp/bigquery_change_history.py:1214

      change_type_column: str = 'change_type',
      change_timestamp_column: str = 'change_timestamp',
      columns: Optional[list[str]] = None,
      row_filter: Optional[str] = None,
      batch_arrow_read: bool = True,
      max_split_rounds: int = 1,
      reshuffle_decompress: bool = True) -> None:
    super().__init__()
    if bq_storage is None:
      raise ImportError(
          'google-cloud-bigquery-storage is required for '
          'ReadBigQueryChangeHistory. Install it with: '
          'pip install google-cloud-bigquery-storage')
    if pyarrow is None:
      raise ImportError(
          'pyarrow is required for ReadBigQueryChangeHistory. '
          'Install it with: pip install pyarrow')
    if change_function not in ('CHANGES', 'APPENDS'):
      raise ValueError(
          f"change_function must be 'CHANGES' or 'APPENDS', "
          f"got '{change_function}'")
    if poll_interval_sec < 15:
      raise ValueError(
          f'poll_interval_sec must be >= 15, got {poll_interval_sec}')
    if buffer_sec < 0:
      raise ValueError(f'buffer_sec must be >= 0, got {buffer_sec}')
    self._table = table
    self._poll_interval_sec = poll_interval_sec
    self._start_time = start_time
    self._stop_time = stop_time
    self._change_function = change_function
    self._buffer_sec = buffer_sec
    self._project = project
    self._temp_dataset = temp_dataset
    self._location = location
    self._change_type_column = change_type_column
    self._change_timestamp_column = change_timestamp_column

View on GitHub (pinned to 12126d8942)

Solutions

  1. Set change_function='CHANGES' for row-level change history.
  2. Set change_function='APPENDS' for append-only tables.
  3. Use the exact uppercase spelling; the check is case-sensitive.

Example fix

// before
ReadFromBigQueryChangeHistory(..., change_function="changes")
// after
ReadFromBigQueryChangeHistory(..., change_function="CHANGES")
Defensive patterns

Strategy: validation

Validate before calling

assert change_function in ("CHANGES", "APPENDS"), \
    f"change_function must be 'CHANGES' or 'APPENDS', got {change_function!r}"

Type guard

from typing import Literal
ChangeFunction = Literal["CHANGES", "APPENDS"]

Try / catch

try:
    transform = ReadFromBigQueryChangeHistory(..., change_function=fn)
except ValueError as e:
    log.error("invalid change_function: %s", e)

Prevention

When it happens

Trigger: Passing change_function='CHANGE' (singular), 'changes' (lowercase), 'INSERTUPDATEDELETE', or any other string outside ('CHANGES', 'APPENDS') when constructing ReadFromBigQueryChangeHistory.

Common situations: Typos or wrong casing when specifying the change function; confusing this option with BigQuery CDC terms like 'MERGE'; copying examples for different APIs.

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