apache/druid · error · QueryDriver.RequestError

The Protobuf class [%s] is not known. Is your protobuf jar o

Error message

The Protobuf class [%s] is not known. Is your protobuf jar on the class path?

What it means

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.

Source

Thrown at extensions-contrib/grpc-query/src/main/java/org/apache/druid/grpc/server/QueryDriver.java:758

            skipColumns
        );
        break;
      default:
        throw new RequestError("Unsupported query result format: " + request.getResultFormat());
    }
    GrpcResultsAccumulator accumulator = new GrpcResultsAccumulator(writer);
    accumulator.push(result);
    return ByteString.copyFrom(out.toByteArray());
  }

  @SuppressWarnings("unchecked")
  private Class<GeneratedMessage> getProtobufClass(final QueryRequest request)
  {
    try {
      return (Class<GeneratedMessage>) Class.forName(request.getProtobufMessageName());
    }
    catch (ClassNotFoundException e) {
      throw new RequestError(
          "The Protobuf class [%s] is not known. Is your protobuf jar on the class path?",
          request.getProtobufMessageName()
      );
    }
    catch (ClassCastException e) {
      throw new RequestError(
          "The class [%s] is not a Protobuf",
          request.getProtobufMessageName()
      );
    }
  }
}

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Verify request.getProtobufMessageName() is the exact fully-qualified class name of a GeneratedMessage subclass (e.g. com.acme.FooResponse).
  2. Deploy the jar containing the generated protobuf class to the server's class path (extensions directory or lib).
  3. Regenerate the client's message name from the same .proto the server uses; check for package relocation changes.
  4. Log/print the requested name server-side and confirm with `jar tf` that the class exists in the deployed artifacts.

Example fix

// before
request.setProtobufMessageName("com.acme.old.Result");
// after
request.setProtobufMessageName("com.acme.v2.ResultRow"); // matches deployed jar
Defensive patterns

Strategy: validation

Validate before calling

// Check the class is loadable before sending the request
try {
  Class.forName(protobufMessageName);
} catch (ClassNotFoundException e) {
  throw new IllegalStateException("protobuf class not on server class path: " + protobufMessageName, e);
}

Type guard

boolean isKnownProtobuf(String name) {
  try {
    return GeneratedMessage.class.isAssignableFrom(Class.forName(name));
  } catch (Throwable t) {
    return false;
  }
}

Try / catch

try {
  return stub.query(req);
} catch (StatusRuntimeException e) {
  if (String.valueOf(e.getStatus().getDescription()).contains("is not known")) {
    throw new IllegalStateException("deploy the jar containing " + req.getProtobufMessageName() + " to the server", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/599921a064adb540. Report an issue: GitHub.