quarkusio/quarkus · error · IllegalArgumentException
Class ${className} already present with different class data
Error message
Class ${className} already present with different class data What it means
LazyIndexer.add() caches raw class bytes by class name. If the same class name is added twice with different byte content, it throws this IllegalArgumentException, because the index cannot decide which definition is authoritative. The class name is normalized from internal '/' form to binary '.' form before the check.
Source
Thrown at core/deployment/src/main/java/io/quarkus/deployment/index/LazyIndexer.java:101
* {@code classData} will be used.
* <p>
* The given class and all annotations found on it will be indexed.
* Unlike the other {@code add} methods, superclasses will <em>not</em> be indexed.
* <p>
* If the same class name has already been added with <em>different</em> class data,
* an exception is thrown.
*/
public void add(String className, byte[] classData) {
Objects.requireNonNull(className);
Objects.requireNonNull(classData);
// this shouldn't happen very often (hopefully...), but there is code out there
// that suggests a class name passed here may be an internal name, not a binary name
className = className.replace('/', '.');
byte[] existingData = classesData.get(className);
if (existingData != null && !Arrays.equals(existingData, classData)) {
throw new IllegalArgumentException("Class " + className + " already present with different class data");
}
classNames.add(className);
classesData.put(className, classData);
}
/**
* Runs the indexing process. All classes added via {@code add()} are indexed
* and the {@link Result} is returned. If a class is not found in the class loader,
* an exception is thrown, unless it is a class of an annotation that is present
* on one of the previously indexed classes.
*/
public Result complete() {
Indexer indexer = new Indexer();
Set<DotName> missingAnnotations = new HashSet<>();
Set<String> alreadySeen = new HashSet<>();
View on GitHub (pinned to e1c734241f)
Solutions
- Run mvn dependency:tree and exclude the duplicate dependency so only one version of the class exists on the deployment classpath
- Check for shading/relocation conflicts (same package+class in two artifacts) and remove the offender
- If you feed the LazyIndexer yourself, ensure each class name is added exactly once with the current bytecode
- Do a clean rebuild to remove stale compiled copies of your own classes
Example fix
// before <dependency> <groupId>com.acme</groupId><artifactId>acme-lib</artifactId><version>1.0</version> </dependency> <dependency> <groupId>com.acme</groupId><artifactId>acme-lib-shaded</artifactId><version>1.0</version> </dependency> // after <dependency> <groupId>com.acme</groupId><artifactId>acme-lib</artifactId><version>1.0</version> </dependency> <!-- shaded duplicate removed -->
Defensive patterns
Strategy: validation
Validate before calling
// Deduplicate classes before feeding LazyIndexer
Map<String, byte[]> unique = new HashMap<>();
for (var entry : classesByName) {
byte[] prev = unique.putIfAbsent(entry.name(), entry.bytes());
if (prev != null && !Arrays.equals(prev, entry.bytes())) {
throw new IllegalArgumentException("Duplicate class with different bytes: " + entry.name());
}
} Try / catch
try {
lazyIndexer.add(className, classData);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("already present with different class data")) {
log.errorf("Duplicate class %s on classpath - run mvn dependency:tree to find the clash", className);
}
throw e;
} Prevention
- Run mvn dependency:tree and exclude duplicate/shaded artifacts
- Never put two versions of the same library on the augmentation classpath
- Avoid mixing fat jars and plain jars containing the same classes
- Clean-build after changing module outputs
When it happens
Trigger: Calling LazyIndexer.add() (directly or via the indexer API) twice for the same class name but supplying different bytecode — e.g. two different jars/shadowed classes contain a class with the same fully-qualified name.
Common situations: Classpath contains duplicate classes from different versions of the same library (shading, fat jars, transitive dependency conflicts); a build tool registers both an old and a newly recompiled version of the same class in one augmentation run.
Related errors
- Failed to index: ${className}, class not present in class lo
- Failed to load CodeGenProvider class from deployment classlo
- Failed to read %s
- Failed to read resources from classpath
- Failed to open class path file <file>
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/776f2c2b1f6bd6d9.
Report an issue: GitHub.