apache/beam · error · TypeError

: table must be of type string; got ValueProvider instead

Error message

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

What it means

ValidateDataflow.create/validate in bigquery.py raises ValueError when both a table and a query are supplied, because BigQuery reads in EXPORT mode must originate from exactly one source — a table export or a query result — and the two are mutually exclusive.

Solutions

  1. Remove the table argument and keep only query
  2. Remove the query argument and keep only table
  3. If the intent was to read a query over a table, express the table inside the query's FROM clause only

Example fix

// before
ReadFromBigQuery(table='proj:ds.tbl', query='SELECT * FROM proj.ds.tbl')
// after
ReadFromBigQuery(query='SELECT * FROM proj.ds.tbl')
Defensive patterns

Strategy: validation

Validate before calling

if isinstance(table, ValueProvider) and output_type == 'BEAM_ROW':
    raise ValueError('BEAM_ROW requires a static string table')

Type guard

def supports_beam_row(table):
    return isinstance(table, str)

Try / catch

try:
    t = ReadFromBigQuery(table=table, output_type='BEAM_ROW')
except TypeError as e:
    if 'ValueProvider' in str(e):
        t = ReadFromBigQuery(table=table, output_type='PYTHON_DICT')

Prevention

When it happens

Trigger: ReadFromBigQuery(table='proj:ds.tbl', query='SELECT ...') — the internal validate() at bigquery.py:3253 fires when both self.table and self.query are non-None.

Common situations: Switching a pipeline from table reads to query reads and forgetting to remove the table argument; config files where both keys are populated; copy-pasted examples merged together.

Related errors


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

Appendix: source

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

          'The method to read from BigQuery must be either EXPORT '
          'or DIRECT_READ.')
    return self._expand_output_type(output_pcollection)

  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):

View on GitHub (pinned to 12126d8942)