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
- Pass exactly one of `row_key` (static string) or `row_key_fn` (callable extracting the key from the beam.Row).
- If keys vary per element, remove the static `row_key` and supply `row_key_fn=lambda row: row['my_key']`.
- 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
- Use a factory/builder that enforces one-of row_key/row_key_fn.
- When migrating to dynamic keys, grep for leftover row_key arguments.
- Document which configuration style your pipeline uses.
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
- Cannot specify both 'labels' and 'index'/'columns'
- Cannot create a temporary directory for root path prefix %s.
- MatchContinuously(timestamp_cursor=True) deduplicates, so it
- %s can be set with either schema_update_options or additiona
- Both a BigQuery table and a query were specified. Please spe
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/8bb21a6f6cf936d0.
Report an issue: GitHub.