shwenzhang/AndResGuard · error · brut.androlib.AndrolibException
readAndWriteHeader size < 0: size=
Error message
readAndWriteHeader size < 0: size=%d
What it means
Header.readAndWriteHeader copies a chunk header while subtracting diffSize (bytes removed earlier, e.g. shortened string entries) from the chunk size. If the adjusted size drops to <= 0 the chunk would be non-positive-length, which is invalid in the arsc format, so the tool throws rather than writing a corrupt header.
Solutions
- Upgrade AndResGuard — later versions fixed diffSize accounting bugs
- Reduce obfuscation aggressiveness (e.g. keep longer resource names, use --keep-extensions style options) so savings stay below chunk size
- Check the resources.arsc for unusually small TYPE chunks via aapt dump
- Report/reproduce with the failing APK and fall back to disabling resource obfuscation for that build
Example fix
// before
andResGuard {
mappingFile = file('old-mapping.txt') // reusing aggressive mapping
}
// after: use a fresh mapping / default setting for this apk
andResGuard {
mappingFile = null
} Defensive patterns
Strategy: validation
Validate before calling
// before obfuscating, check resource counts per type stay in normal ranges
// and avoid reusing aggressive mappings from other apks
if (mappingFile != null && !mappingBelongsToThisApk(mappingFile)) {
throw new GradleException("mappingFile does not match this apk; clear it");
} Try / catch
try {
andResGuardTask.execute();
} catch (AndrolibException e) {
if (e.getMessage().contains("readAndWriteHeader size < 0")) {
logger.warn("diffSize exceeded chunk size; retry with default mapping");
retryWithoutCustomMapping();
} else throw e;
} Prevention
- Don't reuse obfuscation mappings across different APKs
- Keep AndResGuard on the latest fixed version
- Enable resource shrinking so chunks don't contain pathological entries
- Reproduce with aapt dump resources if it persists
When it happens
Trigger: size = in.readInt(); size -= diffSize; yields <= 0 — the diffSize (space saved by resource-name shortening) equals or exceeds the chunk's declared size, which happens with extreme obfuscation savings on tiny chunks or a miscomputed diff upstream.
Common situations: Obfuscating APKs with very small type chunks where the name-shortening savings exceed the chunk size, custom arsc layouts, or an AndResGuard bug in diff accounting with unusual resource tables.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Invalid chunk type: expected=
- Config size < 28
- Invalid chunk type: expected=0x%08x, got=0x%08x
- Could not decode arsc file
- Config size < 28
AI-assisted analysis of shwenzhang/AndResGuard@e4df245d82 (2026-09-12).
Data as JSON: /api/errors/e88acc9c31909306.
Report an issue: GitHub.
Appendix: source
Thrown at AndResGuard-core/src/main/java/com/tencent/mm/androlib/res/decoder/ARSCDecoder.java:1041
return new Header(type, size);
} catch (EOFException ex) {
return new Header(TYPE_NONE, 0);
}
}
public static Header readAndWriteHeader(ExtDataInput in, ExtDataOutput out, int diffSize)
throws IOException, AndrolibException {
short type;
int size;
try {
type = in.readShort();
out.writeShort(type);
short count = in.readShort();
out.writeShort(count);
size = in.readInt();
size -= diffSize;
if (size <= 0) {
throw new AndrolibException(String.format("readAndWriteHeader size < 0: size=%d", size));
}
out.writeInt(size);
} catch (EOFException ex) {
return new Header(TYPE_NONE, 0);
}
return new Header(type, size);
}
}
public static class FlagsOffset {
public final int offset;
public final int count;
public FlagsOffset(int offset, int count) {
this.offset = offset;
this.count = count;
}
}View on GitHub (pinned to e4df245d82)