apache/beam · error · TypeError

%s: table must be of type string; got a callable instead

Error message

%s: table must be of type string; got a callable instead

What it means

In the BEAM_ROW output path (bigquery.py:3123), the table must be a literal string so the schema can be fetched from the BigQuery API at pipeline-construction time. A callable table (e.g. a lambda or function returning the table name) cannot be resolved then, so TypeError is raised.

Source

Thrown at sdks/python/apache_beam/io/gcp/bigquery.py:3123

  def _expand_output_type(self, output_pcollection):
    if self.output_type == 'PYTHON_DICT' or self.output_type is None:
      return output_pcollection
    elif self.output_type == 'BEAM_ROW':
      if self._kwargs.get('query', None) is not None:
        user_schema = bigquery_tools.get_dict_table_schema(
            self.query_output_schema)
        return output_pcollection | bigquery_schema_tools.convert_to_usertype(
            user_schema, self._kwargs.get('selected_fields', None))
      table_details = bigquery_tools.parse_table_reference(
          table=self._kwargs.get("table", None),
          dataset=self._kwargs.get("dataset", None),
          project=self._kwargs.get("project", None))
      if isinstance(self._kwargs['table'], ValueProvider):
        raise TypeError(
            '%s: table must be of type string'
            '; got ValueProvider instead' % self.__class__.__name__)
      elif callable(self._kwargs['table']):
        raise TypeError(
            '%s: table must be of type string'
            '; got a callable instead' % self.__class__.__name__)
      return output_pcollection | bigquery_schema_tools.convert_to_usertype(
          bigquery_tools.BigQueryWrapper().get_table(
              project_id=table_details.projectId,
              dataset_id=table_details.datasetId,
              table_id=table_details.tableId).schema,
          self._kwargs.get('selected_fields', None))
    else:
      raise ValueError(
          'The output type from BigQuery must be either PYTHON_DICT '
          'or BEAM_ROW.')

  def _expand_export(self, pcoll):
    # TODO(https://github.com/apache/beam/issues/20683): Make ReadFromBQ rely
    # on ReadAllFromBQ implementation.
    temp_location = pcoll.pipeline.options.view_as(
        GoogleCloudOptions).temp_location

View on GitHub (pinned to 12126d8942)

Solutions

  1. Pass the table name as a plain string like 'project:dataset.table' or 'dataset.table'
  2. Compute the value before building the pipeline and pass the resulting string
  3. If the table must be dynamic, switch output_type to PYTHON_DICT

Example fix

// before
ReadFromBigQuery(table=lambda: f'{p}:{d}.{t}', output_type='BEAM_ROW')
// after
ReadFromBigQuery(table=f'{p}:{d}.{t}', output_type='BEAM_ROW')
Defensive patterns

Strategy: type-guard

Validate before calling

assert isinstance(table, str) and not callable(table)

Type guard

def is_static_table(table):
    return isinstance(table, str) and not callable(table)

Prevention

When it happens

Trigger: Passing table=lambda: 'project:dataset.table' or any callable while output_type='BEAM_ROW'; passing a bound method or class property object as table.

Common situations: Users wrapping the table name in a helper to compute it from options; misusing ValueProvider-style APIs by passing a function; code refactors where the table was made dynamic.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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