skylot/jadx · error · IOException
Error reading type spec chunk at offset 0x%x
Error message
Error reading type spec chunk at offset 0x%x
What it means
After reading all entries in a type spec chunk (RES_TABLE_TYPE_SPEC_TYPE), the parser checks that the stream position equals the expected end (chunkStart + chunkSize). A mismatch means the declared chunk size does not match the bytes actually consumed by the entryCount flags.
Source
Thrown at jadx-core/src/main/java/jadx/core/xmlgen/ResTableBinaryParser.java:221
LOG.warn("Unknown chunk type {} encountered at offset {}", type, chunkStart);
}
}
}
@SuppressWarnings("unused")
private void parseTypeSpecChunk(long chunkStart) throws IOException {
is.checkInt16(0x0010, "Unexpected type spec header size");
int chunkSize = is.readInt32();
long expectedEndPos = chunkStart + chunkSize;
int id = is.readInt8();
is.skip(3);
int entryCount = is.readInt32();
for (int i = 0; i < entryCount; i++) {
int entryFlag = is.readInt32();
}
if (is.getPos() != expectedEndPos) {
throw new IOException(String.format("Error reading type spec chunk at offset 0x%x", chunkStart));
}
}
private void parseLibraryTypeChunk(long chunkStart) throws IOException {
LOG.trace("parsing library type chunk starting at offset {}", chunkStart);
is.checkInt16(12, "Unexpected header size");
int chunkSize = is.readInt32();
long expectedEndPos = chunkStart + chunkSize;
int count = is.readInt32();
for (int i = 0; i < count; i++) {
int packageId = is.readInt32();
String packageName = is.readString16Fixed(128);
LOG.info("Found resource shared library {}, pkgId: {}", packageName, packageId);
if (is.getPos() > expectedEndPos) {
throw new IOException("reading after chunk end");
}
}
if (is.getPos() != expectedEndPos) {View on GitHub (pinned to e738a26571)
Solutions
- Re-extract resources.arsc from a clean APK
- Upgrade jadx to the latest version
- Report the file to jadx with the chunk offset from the error
- Use jadx --no-res to bypass resource decoding
Example fix
// Skip resource decoding as a workaround: jadxArgs.setSkipResources(true);
Defensive patterns
Strategy: try-catch
Validate before calling
// Verify APK integrity via zip CRC before parsing resources
ZipFile zf = new ZipFile(apk);
zf.getInputStream(zf.getEntry("resources.arsc")).transferTo(OutputStream.nullOutputStream()); // throws on CRC mismatch Try / catch
try {
resTableParser.decode(stream);
} catch (IOException e) {
if (e.getMessage().contains("type spec chunk")) {
LOG.warn("Type spec corruption, skipping resources", e);
jadxArgs.setSkipResources(true);
}
} Prevention
- Validate APK CRC/zip integrity before resource parsing
- Maintain a --no-res fallback
- Report corrupt-but-interesting files to jadx
When it happens
Trigger: parseTypeSpecChunk reads headerSize (validated 0x0010), chunkSize, id, 3 skip bytes, entryCount, then entryCount × 4-byte flags. If getPos() != chunkStart + chunkSize afterward, this IOException is thrown. The discrepancy indicates the entryCount or chunkSize field is inconsistent with the actual data.
Common situations: Obfuscated resources.arsc where entryCount is inflated or deflated. Corrupt resource table from a damaged APK. Custom packers that restructure resource chunks. Newer format with additional trailing fields jadx does not read.
Related errors
- {}, expected: 0x{}, actual: 0x{}, offset: 0x{}
- {}, expected offset: 0x{}, actual: 0x{}
- {}, expected offset not reachable: 0x{}, actual: 0x{}
- reading after chunk end
- Error reading library chunk at offset 0x%x
AI-assisted analysis of skylot/jadx@e738a26571 (2026-08-14).
Data as JSON: /api/errors/a5a9b8bfc4617d18.
Report an issue: GitHub.