quarkusio/quarkus · error · IllegalStateException
Type already defined: ${fullyQualifiedTypeName}
Error message
Type already defined: ${fullyQualifiedTypeName} What it means
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.
Source
Thrown at extensions/grpc/reflection/src/main/java/io/quarkus/grpc/reflection/service/GrpcServerIndex.java:144
throw new IllegalStateException("Service already defined: " + fullyQualifiedServiceName);
}
descriptorsBySymbol.put(fullyQualifiedServiceName, fd);
for (Descriptors.MethodDescriptor method : service.getMethods()) {
String fullyQualifiedMethodName = method.getFullName();
if (descriptorsBySymbol.containsKey(fullyQualifiedMethodName)) {
throw new IllegalStateException(
"Method already defined: " + fullyQualifiedMethodName + " in " + fullyQualifiedServiceName);
}
descriptorsBySymbol.put(fullyQualifiedMethodName, fd);
}
}
private void processType(Descriptors.Descriptor type, FileDescriptor fd,
Map<String, FileDescriptor> descriptorsBySymbol,
Map<String, Map<Integer, FileDescriptor>> descriptorsByExtensionAndNumber) {
String fullyQualifiedTypeName = type.getFullName();
if (descriptorsBySymbol.containsKey(fullyQualifiedTypeName)) {
throw new IllegalStateException("Type already defined: " + fullyQualifiedTypeName);
}
descriptorsBySymbol.put(fullyQualifiedTypeName, fd);
for (Descriptors.FieldDescriptor extension : type.getExtensions()) {
processExtension(extension, fd, descriptorsByExtensionAndNumber);
}
for (Descriptors.Descriptor nestedType : type.getNestedTypes()) {
processType(nestedType, fd, descriptorsBySymbol, descriptorsByExtensionAndNumber);
}
}
private void processExtension(Descriptors.FieldDescriptor extension, FileDescriptor fd,
Map<String, Map<Integer, FileDescriptor>> descriptorsByExtensionAndNumber) {
String extensionName = extension.getContainingType().getFullName();
int extensionNumber = extension.getNumber();
descriptorsByExtensionAndNumber.computeIfAbsent(extensionName,
new Function<String, Map<Integer, FileDescriptor>>() {
@OverrideView on GitHub (pinned to e1c734241f)
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.
Example fix
// before: your own src/main/proto/google/protobuf/empty.proto // after: delete it and use import "google/protobuf/empty.proto";
Defensive patterns
Strategy: validation
Validate before calling
// lint: ensure no message full name is declared twice across protos
Set<String> msgNames = new HashSet<>();
for (ProtoFile f : allProtos)
for (MessageDef m : f.getMessages())
if (!msgNames.add(f.getPackage() + "." + m.getName()))
throw new IllegalStateException("Duplicate message: " + m.getName()); Try / catch
try {
startServer();
} catch (IllegalStateException e) {
if (e.getMessage().startsWith("Type already defined:")) {
// locate the duplicate message declaration (name in message) and de-duplicate
} else throw e;
} Prevention
- 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
When it happens
Trigger: Two proto files declare messages with the same fully qualified name (same proto package, same message name); nested types repeated across duplicated descriptors.
Common situations: 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.
Related errors
- File name already used: ${name}
- Service already defined: ${fullyQualifiedServiceName}
- Method already defined: ${fullyQualifiedMethodName} in ${ful
- Extension name ${extensionName} and number ${extensionNumber
- Code generation failed. Please check the log above for detai
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/e7d6bb7af153e123.
Report an issue: GitHub.