{"record":{"id":"d20b65aa79880af4","repo":"apache/beam","slug":"artifact-location-is-not-specified-please-specify-the","errorCode":null,"errorMessage":"artifact_location is not specified. Please specify the artifact_location for the op %s","messagePattern":"artifact_location is not specified\\. Please specify the artifact_location for the op (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/ml/transforms/tft.py","lineNumber":106,"sourceCode":"    Processing logic for the transformation is defined in the\n    apply_transform() method. If you have a custom transformation that is not\n    supported by the existing transforms, you can extend this class\n    and implement the apply_transform() method.\n    Args:\n      columns: List of column names to apply the transformation.\n    \"\"\"\n    super().__init__(columns)\n    if not columns:\n      raise RuntimeError(\n          \"Columns are not specified. Please specify the column for the \"\n          \" op %s\" % self.__class__.__name__)\n\n  def get_ptransform_for_processing(self, **kwargs) -> beam.PTransform:\n    from apache_beam.ml.transforms.handlers import TFTProcessHandler\n    params = {}\n    artifact_location = kwargs.get('artifact_location')\n    if not artifact_location:\n      raise RuntimeError(\n          \"artifact_location is not specified. Please specify the \"\n          \"artifact_location for the op %s\" % self.__class__.__name__)\n\n    artifact_mode = kwargs.get('artifact_mode')\n    if artifact_mode:\n      params['artifact_mode'] = artifact_mode\n    return TFTProcessHandler(artifact_location=artifact_location, **params)\n\n  @tf.function\n  def _split_string_with_delimiter(self, data, delimiter):\n    \"\"\"\n    only applicable to string columns.\n    \"\"\"\n    data = tf.sparse.to_dense(data)\n    # this method acts differently compared to tf.strings.split\n    # this will split the string based on multiple delimiters while\n    # the latter will split the string based on a single delimiter.\n    fn = lambda data: tf.compat.v1.string_split(","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/ml/transforms/tft.py#L88-L124","documentation":"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.","triggerScenarios":"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.","commonSituations":"Constructing MLTransform(transforms=[...]) without chaining an artifact-location method, or passing artifact_location only to some pipeline branches.","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."],"exampleFix":"# before\nresult = pcoll | MLTransform(tft.ScaleToZScore(columns=['x']))\n\n# after\nresult = pcoll | MLTransform(tft.ScaleToZScore(columns=['x'])).with_write_artifact_location('gs://bucket/artifacts')","handlingStrategy":"validation","validationCode":"def build_mltransform(transforms, artifact_location):\n    if not artifact_location:\n        raise ValueError('artifact_location is required for TFT transforms')\n    return MLTransform(transforms).with_write_artifact_location(artifact_location)","typeGuard":"def has_artifact_location(kwargs: dict) -> bool:\n    loc = kwargs.get('artifact_location')\n    return isinstance(loc, str) and bool(loc.strip())","tryCatchPattern":"try:\n    result = pcoll | build_mltransform(transforms, loc)\nexcept RuntimeError as e:\n    if 'artifact_location is not specified' in str(e):\n        raise ValueError('Chain .with_write_artifact_location(path) or .with_read_artifact_location(path)') from e\n    raise","preventionTips":["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."],"tags":["python","apache-beam","tft","missing-argument"],"backgroundTag":"missing-required-config-field","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}