grpc/grpc-java · error · IllegalArgumentException
(message of wrapped InvalidProtocolBufferException)
Error message
(message of wrapped InvalidProtocolBufferException)
What it means
ProtoLiteUtils' MethodDescriptor Marshaller.parseBytes parses protobuf messages from bytes using the lite runtime with a global extension registry. When the lite parser throws InvalidProtocolBufferException (malformed wire format, unknown fields that cannot be skipped, or missing required extensions), it is rethrown as an IllegalArgumentException wrapping the original exception — so the informative message lives in the cause.
Source
Thrown at protobuf-lite/src/main/java/io/grpc/protobuf/lite/ProtoLiteUtils.java:275
private final T defaultInstance;
MetadataMarshaller(T defaultInstance) {
this.defaultInstance = defaultInstance;
}
@Override
public byte[] toBytes(T value) {
return value.toByteArray();
}
@Override
@SuppressWarnings("unchecked")
public T parseBytes(byte[] serialized) {
try {
return (T) defaultInstance.getParserForType().parseFrom(serialized, globalRegistry);
} catch (InvalidProtocolBufferException ipbe) {
throw new IllegalArgumentException(ipbe);
}
}
}
}
View on GitHub (pinned to 64daddc1f3)
Solutions
- Inspect the cause chain (IllegalArgumentException#getCause) to see the real InvalidProtocolBufferException message identifying the wire-format problem.
- Confirm client and server generated code come from the same .proto version and both use protobuf-lite consistently.
- Verify the RPC method is invoked with the correct request/response message types matching the service definition.
- Check for version skew: redeploy both ends with matching grpc-protobuf-lite and generated stub versions.
Example fix
// before
Foo foo = stub.getFoo(request); // fails with opaque IllegalArgumentException
// after
try {
Foo foo = stub.getFoo(request);
} catch (IllegalArgumentException e) {
log.error("protobuf parse failed", e.getCause()); // InvalidProtocolBufferException details
} Defensive patterns
Strategy: try-catch
Try / catch
try {
T msg = marshaller.parseBytes(serialized);
} catch (IllegalArgumentException e) {
Throwable cause = e.getCause(); // InvalidProtocolBufferException with the real reason
throw new Status.INTERNAL.withCause(cause).withDescription("bad protobuf").asRuntimeException();
} Prevention
- Always inspect getCause() — the wrapper message is uninformative by design.
- Keep generated protobuf code and grpc-protobuf-lite versions in lockstep across services.
- Verify client and server agree on the method's request/response message types.
- Enable wire-format logging when debugging interop between protobuf-lite and full protobuf.
When it happens
Trigger: Any gRPC call using protobuf-lite marshalling where the received message bytes fail protobuf parsing: wrong message type on a method, corrupted/truncated frame, sender using proto2 required fields not set, or a serializer/deserializer version mismatch.
Common situations: Client and server disagree on the RPC message type for a method, mixing protobuf-lite and full protobuf with incompatible generated code, network middleboxes corrupting payloads, or deserializing a response from a service that changed its schema.
Understand the failure class
Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.
Related errors
- Invalid input: expected trace ID at offset ${pos}
- Invalid input: expected span ID at offset ${pos}
- Failed to parse metadata key: %s, type: %s. Error: %s
- Unknown permission rule case: " + permission.getRuleCase()
- Unknown principal identifier case: " + principal.getIdentifi
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/d0b3bc7f4ea218cd.
Report an issue: GitHub.