{"record":{"id":"9c3890233efcdb44","repo":"apache/beam","slug":"transform-must-be-a-subclass-of-baseoperation-got-s-instead","errorCode":null,"errorMessage":"transform must be a subclass of BaseOperation. Got: %s instead.","messagePattern":"transform must be a subclass of BaseOperation\\. Got: (.+?) instead\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/ml/transforms/base.py","lineNumber":468,"sourceCode":"      bad_pcoll = (upstream_errors | beam.Flatten())\n      return pcoll, bad_pcoll  # type: ignore[return-value]\n    return pcoll  # type: ignore[return-value]\n\n  def with_transform(self, transform: MLTransformProvider):\n    \"\"\"\n    Add a transform to the MLTransform pipeline.\n    Args:\n      transform: A BaseOperation instance.\n    Returns:\n      A MLTransform instance.\n    \"\"\"\n    self._validate_transform(transform)\n    self.transforms.append(transform)\n    return self\n\n  def _validate_transform(self, transform):\n    if not isinstance(transform, MLTransformProvider):\n      raise TypeError(\n          'transform must be a subclass of BaseOperation. '\n          'Got: %s instead.' % type(transform))\n\n  def with_exception_handling(\n      self, *, exc_class=Exception, use_subprocess=False, threshold=1):\n    self._with_exception_handling = True\n    self._exception_handling_args = {\n        'exc_class': exc_class,\n        'use_subprocess': use_subprocess,\n        'threshold': threshold\n    }\n    return self\n\n\nclass MLTransformMetricsUsage(beam.PTransform):\n  def __init__(self, ml_transform: MLTransform):\n    self._ml_transform = ml_transform\n    self._ml_transform._counter.inc()","sourceCodeStart":450,"sourceCodeEnd":486,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/ml/transforms/base.py#L450-L486","documentation":"_validate_transform checks that every transform added to MLTransform (via with_transform or the transforms list) is an MLTransformProvider (BaseOperation subclass). Anything else — a raw model handler, callable, or wrong class — triggers this TypeError naming the actual type.","triggerScenarios":"with_transform(SomeModelHandler(...)) instead of with_transform(Embedding(model_handler=...)); passing a class (not an instance); passing a plain function or an object from a different transform library.","commonSituations":"Confusing model handlers (e.g. SentencePieceTokenizer handler) with the transform wrappers (e.g. Tokenize) that MLTransform expects; upgrading Beam where transform class names changed.","solutions":["Wrap the model handler in the appropriate transform class, e.g. with_transform(SentencePieceEmbedding(model_handler=handler, columns=['text'])).","Ensure you pass an instance, not the class itself.","Verify the transform imports from apache_beam.ml.transforms (base operations), not another module."],"exampleFix":"// before\nmltransform.with_transform(SentencePieceTokenizerHandler(vocab_file=vocab))\n// after\nmltransform.with_transform(Tokenize(columns=['text'], model_handler=SentencePieceTokenizer(vocab_file=vocab)))","handlingStrategy":"type-guard","validationCode":"from apache_beam.ml.transforms.base import MLTransformProvider\nassert isinstance(embedding, MLTransformProvider), f'Got {type(embedding)}, expected a BaseOperation subclass'","typeGuard":"def is_valid_transform(t) -> bool:\n    from apache_beam.ml.transforms.base import MLTransformProvider\n    return isinstance(t, MLTransformProvider)","tryCatchPattern":"try:\n    t = mltransform.with_transform(candidate)\nexcept TypeError as e:\n    if 'subclass of BaseOperation' in str(e):\n        raise ValueError(f'{type(candidate)} is a handler; wrap it in a transform like Embedding/Tokenize') from e\n    raise","preventionTips":["Never pass model handlers directly to with_transform; use transform wrapper classes","Pass instances, not classes","Add an isinstance(MLTransformProvider) assert in pipeline-construction tests"],"tags":["python","apache-beam","type-mismatch"],"backgroundTag":"invalid-argument-value","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"}