skylot/jadx · error · JadxRuntimeException

Duplicate class:

Error message

Duplicate class: 

What it means

Thrown by ClsSet.loadFrom when two classes in the input root have the same raw type name. The method iterates root.getClasses(true), builds a map keyed by ArgType.getObject() (the class's internal raw name), and throws if names.put returns a non-null previous value. This indicates a genuine collision in the input set being exported to the classpath format.

Source

Thrown at jadx-core/src/main/java/jadx/core/clsp/ClsSet.java:102

			int methodsCount = Stream.of(classes).mapToInt(clspClass -> clspClass.getMethodsMap().size()).sum();
			LOG.debug("Clst file loaded in {}ms, android api: {}, classes: {}, methods: {}",
					time, androidApiLevel, classes.length, methodsCount);
		}
	}

	public void loadFrom(RootNode root) {
		List<ClassNode> list = root.getClasses(true);
		Map<String, ClspClass> names = new HashMap<>(list.size());
		int k = 0;
		for (ClassNode cls : list) {
			ArgType clsType = cls.getClassInfo().getType();
			String clsRawName = clsType.getObject();
			cls.load();

			ClspClassSource source = getClspClassSource(cls);
			ClspClass nClass = new ClspClass(clsType, k, cls.getAccessFlags().rawValue(), source);
			if (names.put(clsRawName, nClass) != null) {
				throw new JadxRuntimeException("Duplicate class: " + clsRawName);
			}
			k++;
			nClass.setTypeParameters(cls.getGenericTypeParameters());
			nClass.setMethods(getMethodsDetails(cls));
		}
		classes = new ClspClass[k];
		k = 0;
		for (ClassNode cls : list) {
			ClspClass nClass = getCls(cls, names);
			if (nClass == null) {
				throw new JadxRuntimeException("Missing class: " + cls);
			}
			nClass.setParents(makeParentsArray(cls));
			classes[k] = nClass;
			k++;
		}
	}

View on GitHub (pinned to e738a26571)

Solutions

  1. Identify and remove the duplicate class from one of the input sources before running ClsSet.loadFrom.
  2. For multi-dex inputs, use jadx's deduplication options or check if a class is legitimately duplicated and exclude the redundant copy.
  3. Inspect the class name in the error message and search the input APKs/JARs for that class to locate both sources.
  4. If this occurs during a custom jadx-based tool, filter the root's class list to unique names before calling loadFrom.
Defensive patterns

Strategy: validation

Validate before calling

// Pre-deduplicate classes by raw name before calling loadFrom
List<ClassNode> classes = root.getClasses(true);
Map<String, ClassNode> deduped = new LinkedHashMap<>();
for (ClassNode cls : classes) {
    String name = cls.getClassInfo().getType().getObject();
    deduped.putIfAbsent(name, cls);
}
// Check for duplicates
if (deduped.size() < classes.size()) {
    throw new IllegalStateException("Duplicate class names detected in input");
}

Try / catch

try {
    clsSet.loadFrom(root);
} catch (JadxRuntimeException e) {
    if (e.getMessage().startsWith("Duplicate class:")) {
        String className = e.getMessage().substring("Duplicate class: ".length());
        LOG.warn("Skipping duplicate class: {}", className);
        // remove duplicate and retry
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling ClsSet.loadFrom(root) where the RootNode contains two ClassNodes resolving to the same raw class name (e.g., 'com.example.Foo' appearing in two different input files). This can happen with multi-dex inputs that contain duplicate class definitions, or when processing an APK with overlapping library JARs.

Common situations: Decompiling a multi-dex APK where the same class is duplicated across dex files (sometimes due to build tooling issues). Running the classpath export (e.g., via jadx-cli export or internal ClsSet.save) on an input with bundled duplicate libraries. Obfuscated inputs where renaming causes name collisions after processing.

Related errors


AI-assisted analysis of skylot/jadx@e738a26571 (2026-08-14). Data as JSON: /api/errors/4d91f47232e91fad. Report an issue: GitHub.