iBotPeaches/Apktool · critical · IOException

Invalid chunk header: type=0x%04x, headerSize=%s, size=%s

Error message

Invalid chunk header: type=0x%04x, headerSize=%s, size=%s

What it means

ResChunkPullParser validates every chunk header: headerSize must be >= ResChunkHeader.SIZE (8) and the chunk's total size must be >= its header size. Violations mean the file's chunk framing is broken — the stream position can no longer be trusted — so an IOException with the offending type/headerSize/size values is thrown.

Source

Thrown at brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ResChunkPullParser.java:134

        if (mChunkHeader != null) {
            skipChunk();
            mChunkHeader = null;
        }

        if (mIn.position() >= mOffset + mSize) {
            // End of chunks due to size limit.
            mChunkOffset = OFFSET_ENDED;
            return false;
        }

        // Read the chunk header at the current position.
        try {
            mChunkOffset = mIn.position();
            ResChunkHeader chunkHeader = ResChunkHeader.read(mIn);

            if (chunkHeader.headerSize < ResChunkHeader.SIZE
                    || chunkHeader.size < chunkHeader.headerSize) {
                throw new IOException(
                    String.format("Invalid chunk header: type=0x%04x, headerSize=%s, size=%s",
                        chunkHeader.type, chunkHeader.headerSize, chunkHeader.size));
            }

            mChunkHeader = chunkHeader;
            return true;
        } catch (EOFException ignored) {
            // End of chunks due to end of stream.
            mChunkOffset = OFFSET_ENDED;
            return false;
        } catch (IOException ex) {
            throw new IOException("Error while reading chunk header.", ex);
        }
    }

    public int skipChunk() throws IOException {
        if (mChunkHeader == null) {
            throw new IllegalStateException();

View on GitHub (pinned to 79b63384d7)

Solutions

  1. Use the three reported values (type, headerSize, size) to locate the bad chunk in a hex dump — headerSize must be >= 8 and size >= headerSize.
  2. Re-obtain the file/APK from a trusted source and compare checksums.
  3. Validate with aapt2/apkanalyzer; if they also fail, the file itself is broken.
  4. For packer-mangled files, find an unprotected build — header repair is rarely worth it.
Defensive patterns

Strategy: validation

Validate before calling

ByteBuffer buf = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
while (buf.remaining() >= 8) {
    int type = buf.getShort() & 0xFFFF;
    int headerSize = buf.getShort() & 0xFFFF;
    int size = buf.getInt();
    if (headerSize < 8 || size < headerSize || size > buf.remaining()) {
        throw new IOException(String.format("Bad chunk 0x%04x at 0x%x", type, buf.position() - 8));
    }
    buf.position(buf.position() + size - 8);
}

Try / catch

try {
    parser.parse(in);
} catch (IOException e) {
    if (e.getMessage().contains("Invalid chunk header")) {
        // structural corruption — reject file, re-obtain artifact
    }
}

Prevention

When it happens

Trigger: Parsing (arsc or AXML) a file whose chunk headers were corrupted or crafted with impossible sizes — truncation at a chunk boundary, byte-level corruption, deliberate fuzzing, or a packer that rewrote headers incorrectly.

Common situations: Corrupt resource files from interrupted transfers; obfuscated arsc/AXML from protectors; fuzzing corpora; files patched in a hex editor with wrong length fields.

Related errors


AI-assisted analysis of iBotPeaches/Apktool@79b63384d7 (2026-08-14). Data as JSON: /api/errors/91fcbf4d3ed78531. Report an issue: GitHub.