Tencent/tinker · critical · IllegalStateException

bad dex patch file magic:

Error message

bad dex patch file magic: 

What it means

IllegalStateException from DexPatchFile.init: the first bytes of the patch file do not equal the expected 'dexpatch' magic. The stream/file being parsed is not a Tinker dex patch file at all.

Source

Thrown at tinker-commons/src/main/java/com/tencent/tinker/commons/dexpatcher/struct/DexPatchFile.java:81

    private int patchedAnnotationSectionOffset;
    private int patchedEncodedArraySectionOffset;
    private int patchedAnnotationsDirectorySectionOffset;
    private byte[] oldDexSignature;

    public DexPatchFile(File file) throws IOException {
        this.buffer = new DexDataBuffer(ByteBuffer.wrap(FileUtils.readFile(file)));
        init();
    }

    public DexPatchFile(InputStream is) throws IOException {
        this.buffer = new DexDataBuffer(ByteBuffer.wrap(FileUtils.readStream(is)));
        init();
    }

    private void init() {
        byte[] magic = this.buffer.readByteArray(MAGIC.length);
        if (CompareUtils.uArrCompare(magic, MAGIC) != 0) {
            throw new IllegalStateException("bad dex patch file magic: " + Arrays.toString(magic));
        }

        this.version = this.buffer.readShort();
        if (this.version != VERSION_02 && this.version != VERSION_03) {
            throw new IllegalStateException("bad dex patch file version: " + this.version);
        }

        if (this.version > VERSION_02) {
            this.oldDexAPI = this.buffer.readInt();
            this.patchedDexAPI = this.buffer.readInt();
        }
        this.patchedDexSize = this.buffer.readInt();
        this.firstChunkOffset = this.buffer.readInt();
        this.patchedStringIdSectionOffset = this.buffer.readInt();
        this.patchedTypeIdSectionOffset = this.buffer.readInt();
        this.patchedProtoIdSectionOffset = this.buffer.readInt();
        this.patchedFieldIdSectionOffset = this.buffer.readInt();
        this.patchedMethodIdSectionOffset = this.buffer.readInt();

View on GitHub (pinned to 1b7ea02c23)

Solutions

  1. Check the downloaded payload's content type and size before parsing; the printed magic bytes reveal what was actually received
  2. Extract the correctly-named patch entry (e.g., classes.dex patch entries) from the package
  3. Fix the patch download URL/delivery pipeline

Example fix

// before
new DexPatchFile(new FileInputStream(downloadedFile));

// after
byte[] head = new byte[8];
try (InputStream in = new FileInputStream(downloadedFile)) { in.read(head); }
if (!new String(head, "US-ASCII").startsWith("dexpatch")) throw new IOException("not a dex patch payload");
new DexPatchFile(new FileInputStream(downloadedFile));
Defensive patterns

Strategy: validation

Validate before calling

byte[] magic = new byte[8];
try (InputStream is = new BufferedInputStream(new FileInputStream(file))) {
    if (is.read(magic) != magic.length || !"dexpatch".equals(new String(magic, 0, 8, "US-ASCII").trim())) {
        throw new IOException("payload is not a dex patch file");
    }
}
DexPatchFile pf = new DexPatchFile(new FileInputStream(file));

Try / catch

try {
    new DexPatchFile(stream);
} catch (IllegalStateException e) {
    if (String.valueOf(e.getMessage()).startsWith("bad dex patch file magic")) {
        // log received bytes, fix download URL / extraction, do not parse further
    } else { throw e; }
}

Prevention

When it happens

Trigger: Constructing DexPatchFile(File/InputStream) over content that is not a dex patch — e.g., a full dex, a zip entry of the wrong name, an HTML error page from a download endpoint, or a file read from offset 0 of the wrong resource.

Common situations: Patch server returning an error page instead of the patch; extracting the wrong entry from the patch zip; passing the old/new dex where the .dex patch was expected.

Related errors


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