iBotPeaches/Apktool · critical · AndrolibException

Could not decode arsc file.

Error message

Could not decode arsc file.

What it means

Catch-all thrown by BinaryResourceParser.parse when an IOException (other than the structured empty/invalid-chunk checks) escapes while reading the resource table. The original IOException is chained as the cause. It almost always means the arsc is truncated or unreadable at the byte level.

Source

Thrown at brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/BinaryResourceParser.java:144

        ResChunkPullParser parser = new ResChunkPullParser(mIn);
        try {
            if (!nextChunk(parser)) {
                throw new AndrolibException("Input file is empty.");
            }
            if (parser.chunkType() != ResChunkHeader.RES_TABLE_TYPE) {
                throw new AndrolibException("Unexpected chunk: " + parser.chunkName() + " (expected: RES_TABLE_TYPE)");
            }

            parseTable(parser);

            Log.d(TAG, "End of chunks at 0x%08x", mIn.position());

            // We can't use remaining() here, the length of the main stream is unknown.
            if (mIn.available() > 0) {
                Log.d(TAG, "Ignoring trailing data at 0x%08x.", mIn.position());
            }
        } catch (IOException ex) {
            throw new AndrolibException("Could not decode arsc file.", ex);
        }
    }

    public void reset() {
        mIn = null;
        mMissingEntrySpecs.clear();
        mInvalidConfigs.clear();
        mValueStringPool = null;
        mPackageCount = 0;
        mPackage = null;
        mTypeIdOffset = 0;
        mTypeStringPool = null;
        mKeyStringPool = null;
        mHasSparseEntries = false;
        mHasCompactEntries = false;
        if (mEntrySpecFlagsOffsets != null) {
            mEntrySpecFlagsOffsets.clear();
        }

View on GitHub (pinned to 79b63384d7)

Solutions

  1. Read the chained cause — an EOFException-like failure means truncation, other IOExceptions point to the stream/disk.
  2. Re-download or re-extract the APK and verify its checksum before decoding.
  3. Validate the arsc length against the zip central directory entry size (`unzip -v app.apk`).
  4. If the file is intentionally patched/obfuscated, compare with the original from the store/device to see which chunk overruns.
Defensive patterns

Strategy: try-catch

Validate before calling

// fully materialize before parsing to rule out stream issues
byte[] data = Files.readAllBytes(arscPath);
if (data.length < 12) throw new IllegalArgumentException("arsc truncated");

Try / catch

try {
    parser.parse(new ByteArrayInputStream(data));
} catch (AndrolibException e) {
    if ("Could not decode arsc file.".equals(e.getMessage())) {
        Throwable cause = e.getCause(); // EOF => truncation; other IOException => stream/disk
    }
}

Prevention

When it happens

Trigger: An IOException raised inside parseTable (e.g. EOF while reading a string pool, config, or entry) because the declared chunk sizes exceed the actual file length; or a genuine stream failure (closed stream, disk error) while parsing.

Common situations: Partially downloaded APKs; arsc truncated by a repack tool that rewrote sizes; reading from a network stream that dropped mid-parse; zip entry read failures.

Related errors


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