{"record":{"id":"1e7b86cc589dbee3","repo":"grpc/grpc-java","slug":"no-method-bound-for-descriptor-entry-fullmethodn","errorCode":null,"errorMessage":"No method bound for descriptor entry ${fullMethodName}","messagePattern":"No method bound for descriptor entry (.+?)","errorType":"validation","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/io/grpc/ServerServiceDefinition.java","lineNumber":137,"sourceCode":"    /**\n     * Construct new ServerServiceDefinition.\n     */\n    public ServerServiceDefinition build() {\n      ServiceDescriptor serviceDescriptor = this.serviceDescriptor;\n      if (serviceDescriptor == null) {\n        List<MethodDescriptor<?, ?>> methodDescriptors\n            = new ArrayList<>(methods.size());\n        for (ServerMethodDefinition<?, ?> serverMethod : methods.values()) {\n          methodDescriptors.add(serverMethod.getMethodDescriptor());\n        }\n        serviceDescriptor = new ServiceDescriptor(serviceName, methodDescriptors);\n      }\n      Map<String, ServerMethodDefinition<?, ?>> tmpMethods = new HashMap<>(methods);\n      for (MethodDescriptor<?, ?> descriptorMethod : serviceDescriptor.getMethods()) {\n        ServerMethodDefinition<?, ?> removed = tmpMethods.remove(\n            descriptorMethod.getFullMethodName());\n        if (removed == null) {\n          throw new IllegalStateException(\n              \"No method bound for descriptor entry \" + descriptorMethod.getFullMethodName());\n        }\n        if (removed.getMethodDescriptor() != descriptorMethod) {\n          throw new IllegalStateException(\n              \"Bound method for \" + descriptorMethod.getFullMethodName()\n                  + \" not same instance as method in service descriptor\");\n        }\n      }\n      if (tmpMethods.size() > 0) {\n        throw new IllegalStateException(\n            \"No entry in descriptor matching bound method \"\n                + tmpMethods.values().iterator().next().getMethodDescriptor().getFullMethodName());\n      }\n      return new ServerServiceDefinition(serviceDescriptor, methods);\n    }\n  }\n}\n","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/api/src/main/java/io/grpc/ServerServiceDefinition.java#L119-L155","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Add the missing method with builder().addMethod(ServerMethodDefinition or MethodDescriptor) so every descriptor method is bound","Generate both the ServiceDescriptor and ServerServiceDefinition from the same source (protoc-generated code) instead of hand-assembling","Verify each MethodDescriptor's full method name (service + method) matches exactly between the descriptor and the bound method","Re-run code generation after changing the .proto so descriptor and bindings stay in sync"],"exampleFix":"// before: descriptor declares Foo but only Bar was added\nServerServiceDefinition.newBuilder(serviceDescriptor)\n    .addMethod(barMethod)\n    .build(); // IllegalStateException: No method bound for descriptor entry pkg.Svc/Foo\n// after\nServerServiceDefinition.newBuilder(serviceDescriptor)\n    .addMethod(barMethod)\n    .addMethod(fooMethod)\n    .build();","handlingStrategy":"validation","validationCode":"// validate binding completeness before build()\nServiceDescriptor sd = serviceDescriptor;\nSet<String> bound = new HashSet<>();\nfor (ServerMethodDefinition<?,?> m : methods) bound.add(m.getMethodDescriptor().getFullMethodName());\nfor (MethodDescriptor<?,?> d : sd.getMethods()) {\n  if (!bound.contains(d.getFullMethodName())) {\n    throw new IllegalStateException(\"Unbound descriptor method: \" + d.getFullMethodName());\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  definition = builder.build();\n} catch (IllegalStateException e) {\n  if (e.getMessage().startsWith(\"No method bound for descriptor entry\")) {\n    logger.error(\"Descriptor/binding mismatch: {}\", e.getMessage());\n    throw new IllegalArgumentException(\"Regenerate service code; bind all descriptor methods\", e);\n  }\n  throw e;\n}","preventionTips":["Generate ServiceDescriptor and ServerServiceDefinition together from protoc codegen","Never hand-edit generated descriptors; re-run codegen after .proto changes","Ensure every addMethod uses a MethodDescriptor whose full method name matches the service descriptor's","Add a unit test that builds all service definitions at startup"],"tags":["grpc","illegal-state","service-definition","descriptor-mismatch"],"backgroundTag":"internal-invariant-violation","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}