apache/beam · error · ValueError

Transforms should not be passed in read mode. In read mode…

Error message

Transforms should not be passed in read mode. In read mode, the transforms are read from the artifact location.

What it means

MLTransform.__init__ rejects passing transform objects when read_artifact_location is set: in read mode the transform chain must be reconstructed from the previously written artifact, and caller-supplied transforms would silently not be used.

Solutions

  1. Remove the transforms argument when using read_artifact_location.
  2. If you need to re-run with transforms, use write_artifact_location (PRODUCE mode) instead.
  3. Keep separate pipeline code paths (or a flag) for produce vs consume modes.

Example fix

// before
MLTransform(read_artifact_location=loc, transforms=[Embedding(...)])
// after
MLTransform(read_artifact_location=loc)
Defensive patterns

Strategy: validation

Validate before calling

def make_mltransform(**kw):
    if kw.get('read_artifact_location') and kw.get('transforms'):
        raise ValueError('Do not pass transforms in read mode')
    return MLTransform(**kw)

Type guard

def read_mode_config_ok(read_loc, transforms) -> bool:
    return not (read_loc and transforms)

Try / catch

try:
    t = MLTransform(read_artifact_location=loc, transforms=ts)
except ValueError as e:
    if 'read mode' in str(e):
        t = MLTransform(read_artifact_location=loc)
    else:
        raise

Prevention

When it happens

Trigger: MLTransform(read_artifact_location=path, transforms=[...]) — supplying transforms together with read_artifact_location.

Common situations: Reusing a write-mode MLTransform constructor and only swapping write_artifact_location to read_artifact_location without removing the transforms list; templated pipelines that always pass transforms.

Related errors


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

Appendix: source

Thrown at sdks/python/apache_beam/ml/transforms/base.py:368

        are applied in the order they are specified. The input of the
        i-th transform is the output of the (i-1)-th transform. Multi-input
        transforms are not supported yet.
    """
    if read_artifact_location and write_artifact_location:
      raise ValueError(
          'Only one of read_artifact_location or write_artifact_location can '
          'be specified to initialize MLTransform')

    if not read_artifact_location and not write_artifact_location:
      raise ValueError(
          'Either a read_artifact_location or write_artifact_location must be '
          'specified to initialize MLTransform')

    if read_artifact_location:
      artifact_location = read_artifact_location
      artifact_mode = ArtifactMode.CONSUME
      if transforms:
        raise ValueError(
            'Transforms should not be passed in read mode. In read mode, '
            'the transforms are read from the artifact location.')

    else:
      artifact_location = write_artifact_location  # type: ignore[assignment]
      artifact_mode = ArtifactMode.PRODUCE

    self._parent_artifact_location = artifact_location

    self._artifact_mode = artifact_mode
    self.transforms = transforms or []
    self._counter = Metrics.counter(
        MLTransform, f'BeamML_{self.__class__.__name__}')
    self._with_exception_handling = False
    self._exception_handling_args: dict[str, Any] = {}

  def expand(
      self, pcoll: beam.PCollection[ExampleT]

View on GitHub (pinned to 12126d8942)