{"record":{"id":"9c46ec3bb59effd4","repo":"apache/druid","slug":"the-class-s-is-not-a-protobuf","errorCode":null,"errorMessage":"The class [%s] is not a Protobuf","messagePattern":"The class \\[(.+?)\\] is not a Protobuf","errorType":"exception","errorClass":"QueryDriver.RequestError","httpStatus":null,"severity":"error","filePath":"extensions-contrib/grpc-query/src/main/java/org/apache/druid/grpc/server/QueryDriver.java","lineNumber":764,"sourceCode":"    GrpcResultsAccumulator accumulator = new GrpcResultsAccumulator(writer);\n    accumulator.push(result);\n    return ByteString.copyFrom(out.toByteArray());\n  }\n\n  @SuppressWarnings(\"unchecked\")\n  private Class<GeneratedMessage> getProtobufClass(final QueryRequest request)\n  {\n    try {\n      return (Class<GeneratedMessage>) Class.forName(request.getProtobufMessageName());\n    }\n    catch (ClassNotFoundException e) {\n      throw new RequestError(\n          \"The Protobuf class [%s] is not known. Is your protobuf jar on the class path?\",\n          request.getProtobufMessageName()\n      );\n    }\n    catch (ClassCastException e) {\n      throw new RequestError(\n          \"The class [%s] is not a Protobuf\",\n          request.getProtobufMessageName()\n      );\n    }\n  }\n}\n","sourceCodeStart":746,"sourceCodeEnd":771,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-contrib/grpc-query/src/main/java/org/apache/druid/grpc/server/QueryDriver.java#L746-L771","documentation":"In getProtobufClass, Class.forName succeeds but the cast to Class<GeneratedMessage> fails (the loaded class is not a protobuf message type), throwing a ClassCastException that is wrapped in RequestError(\"The class [%s] is not a Protobuf\"). The named class exists but is not a GeneratedMessage, so it cannot be used to encode result rows.","triggerScenarios":"Setting protobufMessageName to a valid FQCN of a non-message class — e.g. a protobuf Builder, an Enum wrapper class, a plain POJO, or the generated outer wrapper class (e.g. com.acme.FooOuterClass) instead of the concrete message type.","commonSituations":"Confusing the outer generated class name with the message class; naming a builder class by appending Builder; loading a class from a jar where the proto was compiled as POJOs (e.g. java_out without lite/full message generation).","solutions":["Use the exact generated message class name (extends GeneratedMessageV3/GeneratedMessage), not the outer file class or Builder.","Verify with Class.forName + GeneratedMessage.class.isAssignableFrom in a test before sending the request.","Regenerate the protobuf classes with the protobuf Java compiler so the named class is a real message type.","Check that the deployed jar is the compiled .proto output, not hand-written POJOs of the same names."],"exampleFix":"// before\nrequest.setProtobufMessageName(\"com.acme.ResultOuterClass\");\n// after\nrequest.setProtobufMessageName(\"com.acme.ResultRow\"); // the GeneratedMessage subclass","handlingStrategy":"type-guard","validationCode":"// Confirm the named class is a protobuf message before use\nClass<?> c = Class.forName(protobufMessageName);\nif (!GeneratedMessage.class.isAssignableFrom(c)) {\n  throw new IllegalArgumentException(protobufMessageName + \" is not a protobuf message\");\n}","typeGuard":"boolean isGeneratedMessage(String name) {\n  try {\n    return GeneratedMessage.class.isAssignableFrom(Class.forName(name));\n  } catch (Throwable t) {\n    return false;\n  }\n}","tryCatchPattern":"try {\n  return stub.query(req);\n} catch (StatusRuntimeException e) {\n  if (String.valueOf(e.getStatus().getDescription()).contains(\"is not a Protobuf\")) {\n    throw new IllegalArgumentException(req.getProtobufMessageName() + \" must be a GeneratedMessage subclass\", e);\n  }\n  throw e;\n}","preventionTips":["Reference the message class (not the outer class or Builder) when filling protobufMessageName.","Validate with GeneratedMessage.class.isAssignableFrom in client-side tests.","Ensure protos are compiled with standard Java message generation, not POJO output.","Keep generated protobuf sources in version control so names are reviewable."],"tags":["grpc","protobuf","type-cast","reflection"],"backgroundTag":"type-mismatch","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}