Tencent/tinker · error · DexException
Expected ${DEX_IN_JAR_NAME} in ${file}
Error message
Expected ${DEX_IN_JAR_NAME} in ${file} What it means
Thrown when Dex(File) opens a zip/jar/apk archive (name has an archive suffix) but the archive contains no entry named classes.dex (DexFormat.DEX_IN_JAR_NAME). The library only knows how to pull the single canonical classes.dex out of an archive; it does not scan for classes2.dex, arbitrary .dex entries, or nested archives.
Source
Thrown at third-party/aosp-dexutils/src/main/java/com/tencent/tinker/android/dex/Dex.java:148
}
if (FileUtils.hasArchiveSuffix(file.getName())) {
ZipFile zipFile = null;
try {
zipFile = new ZipFile(file);
ZipEntry entry = zipFile.getEntry(DexFormat.DEX_IN_JAR_NAME);
if (entry != null) {
InputStream inputStream = null;
try {
inputStream = zipFile.getInputStream(entry);
loadFrom(inputStream, (int) entry.getSize());
} finally {
if (inputStream != null) {
inputStream.close();
}
}
} else {
throw new DexException("Expected " + DexFormat.DEX_IN_JAR_NAME + " in " + file);
}
} finally {
if (zipFile != null) {
try {
zipFile.close();
} catch (Exception e) {
// ignored.
}
}
}
} else if (file.getName().endsWith(".dex")) {
InputStream in = null;
try {
in = new BufferedInputStream(new FileInputStream(file));
loadFrom(in, (int) file.length());
} catch (Exception e) {
throw new DexException(e);
} finally {View on GitHub (pinned to 1b7ea02c23)
Solutions
- Point Dex at the exact dex file: extract classes2.dex (or whichever) from the apk and pass the raw .dex file instead of the archive.
- If you control packaging, ensure a primary classes.dex entry exists at the archive root.
- Inspect the archive first (unzip -l / ZipFile.getEntry) to confirm which classesN.dex entries are present before constructing Dex.
Example fix
// before
Dex dex = new Dex(new File("app.apk")); // fails if only classes2.dex exists
// after
try (ZipFile zip = new ZipFile(apk)) {
ZipEntry e = zip.getEntry("classes2.dex");
try (InputStream in = zip.getInputStream(e)) {
Dex dex = new Dex(in, (int) e.getSize());
}
} Defensive patterns
Strategy: validation
Validate before calling
try (ZipFile zip = new ZipFile(file)) {
if (zip.getEntry("classes.dex") == null) {
// list available dex entries and pick explicitly, or fail with context
throw new IOException("no classes.dex in " + file + " (found: " +
Collections.list(zip.entries()).stream().map(ZipEntry::getName)
.filter(n -> n.endsWith(".dex")).collect(Collectors.toList()) + ")");
}
} Try / catch
catch (DexException e) when message starts with "Expected classes.dex" -> report which classesN.dex entries exist and guide the caller to select one explicitly.
Prevention
- For multidex apks always address a specific classesN.dex entry via ZipFile rather than passing the apk to Dex(File).
- Treat archives as containers: enumerate dex entries yourself, then hand Dex the raw bytes.
When it happens
Trigger: new Dex(new File("app.apk")) where the apk's code lives in classes2.dex..classesN.dex (multidex) with no primary classes.dex; an apk with code stripped; passing a jar that is not a dex container.
Common situations: Multidexed release APKs, apks processed by tools that rename or remove classes.dex (e.g. some obfuscators or 8xx 'compact dex' outputs), or pointing the loader at a resource jar by mistake.
Related errors
- patch %s extract failed (%s).
- can't recognize zip dex format file:%s
- file is null.
- unknown output extension: ${file}
- Unexpected type: ${type}
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/d39a76b1b3b816ab.
Report an issue: GitHub.