apache/dolphinscheduler · error · GrpcParserException

cannot merge json message to protobuf definition type <messa

Error message

cannot merge json message to protobuf definition type <messageTypeName>

What it means

call() merges the user-supplied JSON into a DynamicMessage.Builder for the request type using protobuf's JsonFormat parser. If the JSON is not valid for the protobuf request message type (invalid JSON syntax or type mismatches that cannot be coerced), the InvalidProtocolBufferException is wrapped in GrpcParserException naming the request message type. Note unknown fields are ignored, so only syntax errors and non-coercible value types trigger this.

Source

Thrown at dolphinscheduler-task-plugin/dolphinscheduler-task-grpc/src/main/java/org/apache/dolphinscheduler/plugin/task/grpc/protobufjs/GrpcDynamicService.java:74

        if (isNull(pServiceDescriptor))
            throw new GrpcParserException(
                    "cannot find service <" + methodNameData.getServiceName() + "> from service definition");
        Descriptors.MethodDescriptor pMethodDescriptor =
                pServiceDescriptor.findMethodByName(methodNameData.getRpcName());
        if (isNull(pMethodDescriptor))
            throw new GrpcParserException("cannot find method <" + methodNameData.getRpcName() + "> from service <"
                    + methodNameData.getServiceName() + "> with method list: " + Arrays.toString(pServiceDescriptor
                            .getMethods().stream().map(Descriptors.MethodDescriptor::getName).toArray()));
        MethodDescriptor<DynamicMessage, DynamicMessage> methodDescriptor =
                methodFromProtobuf(pServiceDescriptor, pMethodDescriptor);
        Descriptors.Descriptor requestMessageType = pMethodDescriptor.getInputType();
        Descriptors.Descriptor responseMessageType = pMethodDescriptor.getOutputType();
        DynamicMessage.Builder requestBuilder = DynamicMessage.newBuilder(requestMessageType);
        DynamicMessage.Builder responseBuilder = DynamicMessage.newBuilder(responseMessageType);
        try {
            JsonFormat.parser().ignoringUnknownFields().merge(messageJSON, requestBuilder);
        } catch (InvalidProtocolBufferException ipbe) {
            throw new GrpcParserException(
                    "cannot merge json message to protobuf definition type <" + requestMessageType.getName() + ">",
                    ipbe);
        }
        DynamicMessage request = requestBuilder.build();
        CallOptions callOptions = timeout > 0 ? CallOptions.DEFAULT.withDeadlineAfter(timeout, TimeUnit.MILLISECONDS)
                : CallOptions.DEFAULT;
        responseBuilder.mergeFrom(
                io.grpc.stub.ClientCalls.blockingUnaryCall(channel, methodDescriptor, callOptions, request));
        return responseBuilder.build();
    }

    public static DynamicMessage mergeJSON(Descriptors.FileDescriptor fileDesc, String methodNameWithService,
                                           String messageJSON) {
        MethodName methodNameData = new MethodName(methodNameWithService);
        Descriptors.ServiceDescriptor pServiceDescriptor =
                fileDesc.findServiceByName(methodNameData.getServiceName());
        if (isNull(pServiceDescriptor))
            throw new GrpcParserException(

View on GitHub (pinned to 02eac45a1b)

Solutions

  1. Validate that messageJSON parses as strict JSON (use a JSON linter or JSON.parse) and fix syntax errors like trailing commas or single quotes.
  2. Compare each JSON field's type with the request message definition named in the error and convert values (e.g. '123' -> 123 for int fields).
  3. Remove JSON fields that conflict with proto field types; rely on ignoringUnknownFields() for extra fields but not for mistyped known fields.
  4. Generate the payload with a JSON serializer from a map/object rather than hand-writing or concatenating strings.

Example fix

// before
String json = "{id: 'abc', retries: '3'}"; // unquoted key, string for int32
// after
String json = "{\"id\": \"abc\", \"retries\": 3}";
Defensive patterns

Strategy: validation

Validate before calling

// Validate JSON before calling:
try {
    new com.fasterxml.jackson.databind.ObjectMapper().readTree(messageJSON);
} catch (IOException e) {
    throw new IllegalArgumentException("messageJSON is not valid JSON", e);
}
// Additionally confirm field value types match the proto request definition.

Try / catch

try {
    dynamicService.call(methodNameWithService, messageJSON, timeout);
} catch (GrpcParserException e) {
    if (e.getMessage().startsWith("cannot merge json message") && e.getCause() instanceof InvalidProtocolBufferException) {
        // fix JSON syntax or field types for the named request message type
    }
    throw e;
}

Prevention

When it happens

Trigger: Passing messageJSON that is not syntactically valid JSON (e.g. trailing commas, single quotes, unquoted keys), or whose field values cannot be converted to the proto types (e.g. a string where the proto expects an int32, an object where a string is expected, malformed bytes/base64).

Common situations: Building the JSON payload by string concatenation in the task config instead of a proper JSON serializer; wrong field types after a proto change; numeric fields given as non-numeric strings; passing a JSON array where the request message expects an object.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


AI-assisted analysis of apache/dolphinscheduler@02eac45a1b (2026-09-06). Data as JSON: /api/errors/43085f37972c7afd. Report an issue: GitHub.