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

  1. Use the exact same MethodDescriptor instance when calling addMethod() as the one used to build the ServiceDescriptor
  2. Build the ServiceDescriptor from the same bound methods (descriptor methods must be the instances returned by YourServiceGrpc.getFooMethod())
  3. If constructing manually, first build the method list, then derive the ServiceDescriptor from those same MethodDescriptor objects
  4. 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

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


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/b6c68d3a0d478abf. Report an issue: GitHub.