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
- Chain .with_write_artifact_location(path) (train) or .with_read_artifact_location(path) (inference) onto the MLTransform call.
- Ensure the artifact_location value is a non-empty string path accessible to the runner.
- 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
- Always chain with_write_artifact_location or with_read_artifact_location on TFT MLTransform calls.
- Load artifact_location from a shared pipeline config, not inline literals.
- Add an integration test that constructs every MLTransform with an artifact location.
- Never pass empty-string artifact locations.
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
- Columns are not specified. Please specify the column for…
- A BigQuery table or a query must be specified
- A has been supplied to the model handler, but the required…
- bucket_boundaries requires length_fn to be set.
- combine_fn must be provided
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)