grpc/grpc-java · error · IllegalStateException

No method bound for descriptor entry ${fullMethodName}

Error message

No method bound for descriptor entry ${fullMethodName}

What it means

During ServerServiceDefinition.build(), every MethodDescriptor declared in the ServiceDescriptor must have a corresponding bound ServerMethodDefinition with the identical descriptor instance. If a descriptor method has no bound entry, the builder throws IllegalStateException with 'No method bound for descriptor entry <fullMethodName>'. This is an internal consistency check ensuring the service descriptor and the dispatched method implementations match.

Source

Thrown at api/src/main/java/io/grpc/ServerServiceDefinition.java:137

    /**
     * Construct new ServerServiceDefinition.
     */
    public ServerServiceDefinition build() {
      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. Add the missing method with builder().addMethod(ServerMethodDefinition or MethodDescriptor) so every descriptor method is bound
  2. Generate both the ServiceDescriptor and ServerServiceDefinition from the same source (protoc-generated code) instead of hand-assembling
  3. Verify each MethodDescriptor's full method name (service + method) matches exactly between the descriptor and the bound method
  4. Re-run code generation after changing the .proto so descriptor and bindings stay in sync

Example fix

// before: descriptor declares Foo but only Bar was added
ServerServiceDefinition.newBuilder(serviceDescriptor)
    .addMethod(barMethod)
    .build(); // IllegalStateException: No method bound for descriptor entry pkg.Svc/Foo
// after
ServerServiceDefinition.newBuilder(serviceDescriptor)
    .addMethod(barMethod)
    .addMethod(fooMethod)
    .build();
Defensive patterns

Strategy: validation

Validate before calling

// validate binding completeness before build()
ServiceDescriptor sd = serviceDescriptor;
Set<String> bound = new HashSet<>();
for (ServerMethodDefinition<?,?> m : methods) bound.add(m.getMethodDescriptor().getFullMethodName());
for (MethodDescriptor<?,?> d : sd.getMethods()) {
  if (!bound.contains(d.getFullMethodName())) {
    throw new IllegalStateException("Unbound descriptor method: " + d.getFullMethodName());
  }
}

Try / catch

try {
  definition = builder.build();
} catch (IllegalStateException e) {
  if (e.getMessage().startsWith("No method bound for descriptor entry")) {
    logger.error("Descriptor/binding mismatch: {}", e.getMessage());
    throw new IllegalArgumentException("Regenerate service code; bind all descriptor methods", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Constructing a ServerServiceDefinition via builder().addMethod(descriptor-with-service-name) while the ServiceDescriptor contains a method whose full method name was never added (e.g. methods list and serviceDescriptor built from different MethodDescriptor sets, custom service descriptor with a method name not bound); programmatic assembly where a method descriptor's service name differs so the lookup by fullMethodName misses.

Common situations: Hand-writing ServiceDescriptor and ServerServiceDefinition separately and adding a new RPC to one but not the other; codegen mismatches or manually modified descriptors; typos in method names causing full-method-name mismatch between the two collections.

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/1e7b86cc589dbee3. Report an issue: GitHub.