{"record":{"id":"599921a064adb540","repo":"apache/druid","slug":"the-protobuf-class-s-is-not-known-is-your-prot","errorCode":null,"errorMessage":"The Protobuf class [%s] is not known. Is your protobuf jar on the class path?","messagePattern":"The Protobuf class \\[(.+?)\\] is not known\\. Is your protobuf jar on the class path\\?","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":758,"sourceCode":"            skipColumns\n        );\n        break;\n      default:\n        throw new RequestError(\"Unsupported query result format: \" + request.getResultFormat());\n    }\n    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":740,"sourceCodeEnd":771,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-contrib/grpc-query/src/main/java/org/apache/druid/grpc/server/QueryDriver.java#L740-L771","documentation":"When the request specifies a protobuf message name for results, getProtobufClass loads it with Class.forName. If the named class is absent from the server's class path, a ClassNotFoundException is wrapped in RequestError(\"The Protobuf class [%s] is not known. Is your protobuf jar on the class path?\"). The server cannot construct the response message type the client asked for.","triggerScenarios":"QueryRequest.protobufMessageName is set to a class name (FQCN) that is not loadable in the gRPC server's JVM — misspelled FQCN, class from a jar not shipped to the server, or proto package renamed in a version upgrade.","commonSituations":"Client and server generated protobuf classes differ (package/name changed between proto versions); the custom message jar was never deployed to the Druid extension directory; typo in the message name; shade/relocation changed the class package.","solutions":["Verify request.getProtobufMessageName() is the exact fully-qualified class name of a GeneratedMessage subclass (e.g. com.acme.FooResponse).","Deploy the jar containing the generated protobuf class to the server's class path (extensions directory or lib).","Regenerate the client's message name from the same .proto the server uses; check for package relocation changes.","Log/print the requested name server-side and confirm with `jar tf` that the class exists in the deployed artifacts."],"exampleFix":"// before\nrequest.setProtobufMessageName(\"com.acme.old.Result\");\n// after\nrequest.setProtobufMessageName(\"com.acme.v2.ResultRow\"); // matches deployed jar","handlingStrategy":"validation","validationCode":"// Check the class is loadable before sending the request\ntry {\n  Class.forName(protobufMessageName);\n} catch (ClassNotFoundException e) {\n  throw new IllegalStateException(\"protobuf class not on server class path: \" + protobufMessageName, e);\n}","typeGuard":"boolean isKnownProtobuf(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 known\")) {\n    throw new IllegalStateException(\"deploy the jar containing \" + req.getProtobufMessageName() + \" to the server\", e);\n  }\n  throw e;\n}","preventionTips":["Copy-paste the FQCN from the generated class rather than typing it.","Ensure the jar with generated protobuf classes is bundled with the server extension.","Generate the protobufMessageName from the same compiled .proto used by the server.","Add a startup check that resolves configured message names via Class.forName."],"tags":["grpc","protobuf","classpath","reflection"],"backgroundTag":"class-not-found","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"}