apache/beam · error · RuntimeError

artifact_location is not specified. Please specify the…

Error message

artifact_location is not specified. Please specify the artifact_location for the op %s

What it means

TFT-based ops need an artifact_location where computed statistics/vocabularies are stored and retrieved. get_ptransform_for_processing reads artifact_location from the processing kwargs and raises a RuntimeError if it is missing or empty, because the TFTProcessHandler cannot function without it.

Solutions

  1. Chain .with_write_artifact_location(path) (train) or .with_read_artifact_location(path) (inference) onto the MLTransform call.
  2. Ensure the artifact_location value is a non-empty string path accessible to the runner.
  3. If building kwargs manually, include artifact_location in the dict passed to processing.

Example fix

# before
result = pcoll | MLTransform(tft.ScaleToZScore(columns=['x']))

# after
result = pcoll | MLTransform(tft.ScaleToZScore(columns=['x'])).with_write_artifact_location('gs://bucket/artifacts')
Defensive patterns

Strategy: validation

Validate before calling

def build_mltransform(transforms, artifact_location):
    if not artifact_location:
        raise ValueError('artifact_location is required for TFT transforms')
    return MLTransform(transforms).with_write_artifact_location(artifact_location)

Type guard

def has_artifact_location(kwargs: dict) -> bool:
    loc = kwargs.get('artifact_location')
    return isinstance(loc, str) and bool(loc.strip())

Try / catch

try:
    result = pcoll | build_mltransform(transforms, loc)
except RuntimeError as e:
    if 'artifact_location is not specified' in str(e):
        raise ValueError('Chain .with_write_artifact_location(path) or .with_read_artifact_location(path)') from e
    raise

Prevention

When it happens

Trigger: Calling MLTransform with TFT transform configs but forgetting .with_write_artifact_location() / .with_read_artifact_location(), or the artifact_location kwarg being None/empty string when ApplyTransforms builds the PTransform.

Common situations: Constructing MLTransform(transforms=[...]) without chaining an artifact-location method, or passing artifact_location only to some pipeline branches.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at sdks/python/apache_beam/ml/transforms/tft.py:106

    Processing logic for the transformation is defined in the
    apply_transform() method. If you have a custom transformation that is not
    supported by the existing transforms, you can extend this class
    and implement the apply_transform() method.
    Args:
      columns: List of column names to apply the transformation.
    """
    super().__init__(columns)
    if not columns:
      raise RuntimeError(
          "Columns are not specified. Please specify the column for the "
          " op %s" % self.__class__.__name__)

  def get_ptransform_for_processing(self, **kwargs) -> beam.PTransform:
    from apache_beam.ml.transforms.handlers import TFTProcessHandler
    params = {}
    artifact_location = kwargs.get('artifact_location')
    if not artifact_location:
      raise RuntimeError(
          "artifact_location is not specified. Please specify the "
          "artifact_location for the op %s" % self.__class__.__name__)

    artifact_mode = kwargs.get('artifact_mode')
    if artifact_mode:
      params['artifact_mode'] = artifact_mode
    return TFTProcessHandler(artifact_location=artifact_location, **params)

  @tf.function
  def _split_string_with_delimiter(self, data, delimiter):
    """
    only applicable to string columns.
    """
    data = tf.sparse.to_dense(data)
    # this method acts differently compared to tf.strings.split
    # this will split the string based on multiple delimiters while
    # the latter will split the string based on a single delimiter.
    fn = lambda data: tf.compat.v1.string_split(

View on GitHub (pinned to 12126d8942)