apache/beam · error · ValueError

Please specify exactly one of `row_key` or a lambda function

Error message

Please specify exactly one of `row_key` or a lambda function with `row_key_fn` to extract the row key from the input row.

What it means

Raised by BigTableEnrichmentHandler.__init__ when row-key configuration is ambiguous or missing: the handler requires exactly one way to determine the BigTable row key — either a static `row_key` string or a `row_key_fn` callable that extracts it from the input row. Passing neither, or passing both, is rejected at construction time.

Source

Thrown at sdks/python/apache_beam/transforms/enrichment_handlers/bigtable.py:95

      app_profile_id: str = None,  # type: ignore[assignment]
      encoding: str = 'utf-8',
      row_key_fn: Optional[RowKeyFn] = None,
      exception_level: ExceptionLevel = ExceptionLevel.WARN,
      include_timestamp: bool = False,
  ):
    self._project_id = project_id
    self._instance_id = instance_id
    self._table_id = table_id
    self._row_key = row_key
    self._row_filter = row_filter
    self._app_profile_id = app_profile_id
    self._encoding = encoding
    self._row_key_fn = row_key_fn
    self._exception_level = exception_level
    self._include_timestamp = include_timestamp
    if ((not self._row_key_fn and not self._row_key) or
        bool(self._row_key_fn and self._row_key)):
      raise ValueError(
          "Please specify exactly one of `row_key` or a lambda "
          "function with `row_key_fn` to extract the row key "
          "from the input row.")

  def __enter__(self):
    """connect to the Google BigTable cluster."""
    self.client = Client(project=self._project_id)
    self.instance = self.client.instance(self._instance_id)
    self._table = bigtable.table.Table(
        table_id=self._table_id,
        instance=self.instance,
        app_profile_id=self._app_profile_id)

  def __call__(self, request: beam.Row, *args, **kwargs):
    """
    Reads a row from the GCP BigTable and returns
    a `Tuple` of request and response.

View on GitHub (pinned to 12126d8942)

Solutions

  1. Pass exactly one of `row_key` (static string) or `row_key_fn` (callable extracting the key from the beam.Row).
  2. If keys vary per element, remove the static `row_key` and supply `row_key_fn=lambda row: row['my_key']`.
  3. If the key is always the same, keep `row_key='...'` and delete the `row_key_fn` argument.

Example fix

# before (both supplied)
h = bigtable.BigTableEnrichmentHandler(instance_id=i, table_id=t, row_key='k', row_key_fn=lambda r: r['id'])
# after (dynamic key only)
h = bigtable.BigTableEnrichmentHandler(instance_id=i, table_id=t, row_key_fn=lambda r: r['id'])
Defensive patterns

Strategy: validation

Validate before calling

def make_bigtable_handler(row_key=None, row_key_fn=None, **kw):
    if bool(row_key) == bool(row_key_fn):
        raise ValueError('specify exactly one of row_key or row_key_fn')
    return bigtable.BigTableEnrichmentHandler(row_key=row_key, row_key_fn=row_key_fn, **kw)

Type guard

def valid_row_key_config(row_key, row_key_fn):
    return (row_key is None) != (row_key_fn is None)

Try / catch

try:
    handler = bigtable.BigTableEnrichmentHandler(**cfg)
except ValueError as e:
    logging.error('row key config invalid: %s', e)
    raise

Prevention

When it happens

Trigger: bigtable.BigTableEnrichmentHandler(instance_id=..., table_id=...) with neither row_key nor row_key_fn; or with both row_key='somekey' and row_key_fn=lambda row: ... simultaneously.

Common situations: Copy-pasting example code that sets row_key and then adding a row_key_fn for dynamic keys; forgetting both arguments when converting a handler from static to dynamic keys; refactoring that left a stale row_key in place.

Related errors


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