apache/beam · error · ValueError

Invalid input specified. It must be a dict.

Error message

Invalid input {pcolls} specified. It must be a dict.

What it means

Thrown by _validate_input in apache_beam/yaml/yaml_join.py when the join transform's inputs are not a dict mapping input tags to PCollections. SQL join requires named inputs so equality and join-type specs can reference them.

Solutions

  1. Pass inputs as a dict with at least two named tags.
  2. Check the pipeline spec: the 'input' field of Join must be an object/map, not an array.
  3. Validate the inputs structure before expand().

Example fix

// before
SqlJoin({'inputs': [pc1, pc2]})
// after
SqlJoin({'inputs': {'input1': pc1, 'input2': pc2}})
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(inputs, dict):
    raise TypeError('Join inputs must be a dict of tag -> PCollection')

Type guard

def is_valid_join_inputs(x):
    return isinstance(x, dict) and all(isinstance(v, PCollection) for v in x.values())

Try / catch

try:
    join.expand(inputs)
except ValueError as e:
    if 'It must be a dict' in str(e):
        inputs = {f'input{i+1}': pc for i, pc in enumerate(inputs)}

Prevention

When it happens

Trigger: Calling _SqlJoinTransform.expand (directly or via YAML) with inputs given as a list, tuple, or single PCollection instead of a dict like {'input1': pc1, 'input2': pc2}.

Common situations: Programmatic use of the YAML join transform where a developer passes a list of PCollections; YAML pipeline definitions where 'input' was serialized as an array instead of a mapping.

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

Appendix: source

Thrown at sdks/python/apache_beam/yaml/yaml_join.py:30

# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

"""This module defines the Join operation."""
from typing import Any
from typing import Optional
from typing import Union

import apache_beam as beam
from apache_beam.yaml import yaml_provider


def _validate_input(pcolls):
  error_prefix = f'Invalid input {pcolls} specified.'
  if not isinstance(pcolls, dict):
    raise ValueError(f'{error_prefix} It must be a dict.')
  if len(pcolls) < 2:
    raise ValueError(
        f'{error_prefix} There should be at least 2 inputs to join.')


def _validate_type(type, pcolls):
  error_prefix = f'Invalid value "{type}" for "type".'
  if not isinstance(type, dict) and not isinstance(type, str):
    raise ValueError(f'{error_prefix} It must be a dict or a str.')
  if isinstance(type, dict):
    error = ValueError(
        f'{error_prefix} When specifying a dict for type, '
        f'it must follow this format: '
        f'{{"outer": [list of inputs to outer join]}}. '
        f'Example: {{"outer": ["input1", "input2"]}}')
    if (len(type) != 1 or next(iter(type)) != 'outer' or
        not isinstance(type['outer'], list)):
      raise error

View on GitHub (pinned to 12126d8942)