{"record":{"id":"2e0e9a48191f0934","repo":"apache/beam","slug":"expected-a-subclass-of-proto-message-but-got-a-s","errorCode":null,"errorMessage":"Expected a subclass of proto.Message, but got a %s","messagePattern":"Expected a subclass of proto\\.Message, but got a (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/coders/coders.py","lineNumber":1252,"sourceCode":"    return coder_impl.ProtoPlusCoderImpl(self.proto_plus_message_type)\n\n  def is_deterministic(self):\n    return True\n\n  def __eq__(self, other):\n    return (\n        type(self) == type(other) and\n        self.proto_plus_message_type == other.proto_plus_message_type)\n\n  def __hash__(self):\n    return hash(self.proto_plus_message_type)\n\n  @classmethod\n  def from_type_hint(cls, typehint, unused_registry):\n    if issubclass(typehint, proto.Message):\n      return cls(typehint)\n    else:\n      raise ValueError(\n          'Expected a subclass of proto.Message, but got a %s' % typehint)\n\n  def to_type_hint(self):\n    return self.proto_plus_message_type\n\n\nAVRO_GENERIC_CODER_URN = \"beam:coder:avro:generic:v1\"\n\n\nclass AvroGenericCoder(FastCoder):\n  \"\"\"A coder used for AvroRecord values.\"\"\"\n  def __init__(self, schema):\n    self.schema = schema\n\n  def _create_impl(self):\n    return coder_impl.AvroCoderImpl(self.schema)\n\n  def is_deterministic(self):","sourceCodeStart":1234,"sourceCodeEnd":1270,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/coders/coders.py#L1234-L1270","documentation":"ProtoPlusCoder wraps proto-plus (new-style) protobuf messages. from_type_hint requires the typehint to be a subclass of proto.Message; classic google.protobuf.message.Message subclasses or arbitrary classes raise ValueError.","triggerScenarios":"Creating a ProtoPlusCoder via from_type_hint with a classic protobuf class or any non-proto-plus class as the typehint.","commonSituations":"Codebases migrating between protobuf APIs passing old generated pb2 classes where ProtoPlusCoder is expected (or vice versa); misconfigured coders in pipeline options.","solutions":["Pass a proto-plus message class (one generated/converted with the new protobuf API) to ProtoPlusCoder","Use ProtoCoder (or coders.registry) for classic google.protobuf.message.Message subclasses","Normalize the typehint with proto_utils helpers to pick the right coder"],"exampleFix":"// before\ncoder = ProtoPlusCoder.from_type_hint(school_pb2.Student, registry)\n// after\ncoder = ProtoCoder.from_type_hint(school_pb2.Student, registry)","handlingStrategy":"type-guard","validationCode":"import proto\nis_proto_plus = isinstance(typehint, type) and issubclass(typehint, proto.Message)","typeGuard":"def is_proto_plus_class(t) -> bool:\n    import proto\n    return isinstance(t, type) and issubclass(t, proto.Message)","tryCatchPattern":"try:\n    coder = ProtoPlusCoder.from_type_hint(typehint, registry)\nexcept ValueError:\n    from apache_beam.coders import ProtoCoder\n    coder = ProtoCoder.from_type_hint(typehint, registry)","preventionTips":["Match the coder class to the protobuf API flavor in use","Rely on coders.registry.get_coder instead of forcing a specific proto coder","Keep proto-plus and classic protobuf usage consistent across the pipeline"],"tags":["python","protobuf","coders","apache-beam"],"backgroundTag":"type-mismatch","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}