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

  1. 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.
  2. If you control packaging, ensure a primary classes.dex entry exists at the archive root.
  3. 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

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


AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14). Data as JSON: /api/errors/d39a76b1b3b816ab. Report an issue: GitHub.