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

  1. Upgrade AndResGuard — later versions fixed diffSize accounting bugs
  2. Reduce obfuscation aggressiveness (e.g. keep longer resource names, use --keep-extensions style options) so savings stay below chunk size
  3. Check the resources.arsc for unusually small TYPE chunks via aapt dump
  4. 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

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


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)