grpc/grpc-java · error · IllegalStateException
Bound method for ${fullMethodName} not same instance as meth
Error message
Bound method for ${fullMethodName} not same instance as method in service descriptor What it means
ServerServiceDefinition.Builder.build() verifies that every method bound via addMethod() refers to the exact same MethodDescriptor instance stored in the service descriptor. If a bound method's descriptor differs by instance (even if logically equal) from the one in the ServiceDescriptor, this IllegalStateException is thrown to protect against internal inconsistency between the builder's bound methods and the service descriptor.
Source
Thrown at api/src/main/java/io/grpc/ServerServiceDefinition.java:141
ServiceDescriptor serviceDescriptor = this.serviceDescriptor;
if (serviceDescriptor == null) {
List<MethodDescriptor<?, ?>> methodDescriptors
= new ArrayList<>(methods.size());
for (ServerMethodDefinition<?, ?> serverMethod : methods.values()) {
methodDescriptors.add(serverMethod.getMethodDescriptor());
}
serviceDescriptor = new ServiceDescriptor(serviceName, methodDescriptors);
}
Map<String, ServerMethodDefinition<?, ?>> tmpMethods = new HashMap<>(methods);
for (MethodDescriptor<?, ?> descriptorMethod : serviceDescriptor.getMethods()) {
ServerMethodDefinition<?, ?> removed = tmpMethods.remove(
descriptorMethod.getFullMethodName());
if (removed == null) {
throw new IllegalStateException(
"No method bound for descriptor entry " + descriptorMethod.getFullMethodName());
}
if (removed.getMethodDescriptor() != descriptorMethod) {
throw new IllegalStateException(
"Bound method for " + descriptorMethod.getFullMethodName()
+ " not same instance as method in service descriptor");
}
}
if (tmpMethods.size() > 0) {
throw new IllegalStateException(
"No entry in descriptor matching bound method "
+ tmpMethods.values().iterator().next().getMethodDescriptor().getFullMethodName());
}
return new ServerServiceDefinition(serviceDescriptor, methods);
}
}
}
View on GitHub (pinned to 64daddc1f3)
Solutions
- Use the exact same MethodDescriptor instance when calling addMethod() as the one used to build the ServiceDescriptor
- Build the ServiceDescriptor from the same bound methods (descriptor methods must be the instances returned by YourServiceGrpc.getFooMethod())
- If constructing manually, first build the method list, then derive the ServiceDescriptor from those same MethodDescriptor objects
- Log and compare full method names plus object identity (System.identityHashCode) to find which descriptor was duplicated
Example fix
// before MethodDescriptor<Req, Resp> generated = FooGrpc.getBarMethod(); MethodDescriptor<Req, Resp> custom = generated.toBuilder().build(); // new instance builder.addMethod(custom); // ServiceDescriptor holds `generated` -> mismatch // after builder.addMethod(FooGrpc.getBarMethod()); // same instance as in the descriptor
Defensive patterns
Strategy: validation
Validate before calling
if (boundDesc != serviceDescriptor.getMethod(fullMethodName)) {
throw new IllegalStateException("Descriptor instance mismatch for " + fullMethodName);
} Try / catch
try {
def = builder.build();
} catch (IllegalStateException e) {
throw new ConfigurationException("Service definition mismatch: " + e.getMessage(), e);
} Prevention
- Reuse code-generated MethodDescriptor constants instead of building new ones
- Derive the ServiceDescriptor from the same method instances passed to addMethod()
- Add an identity assert (assertSame) in tests for each bound method
When it happens
Trigger: Calling build() on ServerServiceDefinition.Builder after addMethod() was given a MethodDescriptor that is a different object instance than the MethodDescriptor recorded in the ServiceDescriptor for the same full method name — e.g. constructing descriptors independently instead of reusing the same instance.
Common situations: Custom server builders that generate MethodDescriptors in two places; code that rebuilds or re-serializes a descriptor; misuse of ServerServiceDefinition.Builder with a ServiceDescriptor created from different descriptor objects; copy-pasted gRPC codegen artifacts.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- No entry in descriptor matching bound method ${fullMethodNam
- No ALTS context information found
- Can't set TLS settings for ALTS
- Counter has overflowed.
- Invalid frame length ${dataLength}
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/b6c68d3a0d478abf.
Report an issue: GitHub.