{"record":{"id":"e7d6bb7af153e123","repo":"quarkusio/quarkus","slug":"type-already-defined-fullyqualifiedtypename","errorCode":null,"errorMessage":"Type already defined: ${fullyQualifiedTypeName}","messagePattern":"Type already defined: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/grpc/reflection/src/main/java/io/quarkus/grpc/reflection/service/GrpcServerIndex.java","lineNumber":144,"sourceCode":"            throw new IllegalStateException(\"Service already defined: \" + fullyQualifiedServiceName);\n        }\n        descriptorsBySymbol.put(fullyQualifiedServiceName, fd);\n        for (Descriptors.MethodDescriptor method : service.getMethods()) {\n            String fullyQualifiedMethodName = method.getFullName();\n            if (descriptorsBySymbol.containsKey(fullyQualifiedMethodName)) {\n                throw new IllegalStateException(\n                        \"Method already defined: \" + fullyQualifiedMethodName + \" in \" + fullyQualifiedServiceName);\n            }\n            descriptorsBySymbol.put(fullyQualifiedMethodName, fd);\n        }\n    }\n\n    private void processType(Descriptors.Descriptor type, FileDescriptor fd,\n            Map<String, FileDescriptor> descriptorsBySymbol,\n            Map<String, Map<Integer, FileDescriptor>> descriptorsByExtensionAndNumber) {\n        String fullyQualifiedTypeName = type.getFullName();\n        if (descriptorsBySymbol.containsKey(fullyQualifiedTypeName)) {\n            throw new IllegalStateException(\"Type already defined: \" + fullyQualifiedTypeName);\n        }\n        descriptorsBySymbol.put(fullyQualifiedTypeName, fd);\n        for (Descriptors.FieldDescriptor extension : type.getExtensions()) {\n            processExtension(extension, fd, descriptorsByExtensionAndNumber);\n        }\n        for (Descriptors.Descriptor nestedType : type.getNestedTypes()) {\n            processType(nestedType, fd, descriptorsBySymbol, descriptorsByExtensionAndNumber);\n        }\n    }\n\n    private void processExtension(Descriptors.FieldDescriptor extension, FileDescriptor fd,\n            Map<String, Map<Integer, FileDescriptor>> descriptorsByExtensionAndNumber) {\n        String extensionName = extension.getContainingType().getFullName();\n        int extensionNumber = extension.getNumber();\n\n        descriptorsByExtensionAndNumber.computeIfAbsent(extensionName,\n                new Function<String, Map<Integer, FileDescriptor>>() {\n                    @Override","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/grpc/reflection/src/main/java/io/quarkus/grpc/reflection/service/GrpcServerIndex.java#L126-L162","documentation":"Reflection index building records every message type (Descriptors.Descriptor) by its fully qualified name. processType throws this IllegalStateException if a type with that full name (package.MessageName, including nested types) was already registered by a previously processed FileDescriptor or nested type.","triggerScenarios":"Two proto files declare messages with the same fully qualified name (same proto package, same message name); nested types repeated across duplicated descriptors.","commonSituations":"Vendoring/copying a proto (e.g. google/protobuf/*.proto or well-known types) into your own package, colliding with a dependency that also ships it; two SDK versions bundling the same message protos.","solutions":["Never re-vendor protos already shipped by dependencies (e.g. don't copy google/protobuf/empty.proto); import them instead.","Give duplicate messages distinct proto packages or names.","Exclude the dependency shipping the duplicate proto (mvn dependency:tree + exclusion).","Clean rebuild to flush stale generated descriptors."],"exampleFix":"// before: your own src/main/proto/google/protobuf/empty.proto\n// after: delete it and use\nimport \"google/protobuf/empty.proto\";","handlingStrategy":"validation","validationCode":"// lint: ensure no message full name is declared twice across protos\nSet<String> msgNames = new HashSet<>();\nfor (ProtoFile f : allProtos)\n  for (MessageDef m : f.getMessages())\n    if (!msgNames.add(f.getPackage() + \".\" + m.getName()))\n      throw new IllegalStateException(\"Duplicate message: \" + m.getName());","typeGuard":null,"tryCatchPattern":"try {\n    startServer();\n} catch (IllegalStateException e) {\n    if (e.getMessage().startsWith(\"Type already defined:\")) {\n        // locate the duplicate message declaration (name in message) and de-duplicate\n    } else throw e;\n}","preventionTips":["Import well-known types instead of re-vendoring them","Use distinct proto packages per module","CI lint for duplicate message full names","Exclude transitive dependencies bundling the same protos"],"tags":["grpc","reflection","protobuf","duplicate-type"],"backgroundTag":"duplicate-proto-symbol","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}