shwenzhang/AndResGuard · error · AndrolibException

writeSpecNameStringBlock

Error message

writeSpecNameStringBlock %s UTF-8 length is different name %d, tempByte %d

What it means

When writing a spec-name string in UTF-8 mode, the writer reserves 2 bytes for the two length fields and casts name.length() to byte. Java's String.length() counts UTF-16 code units, which differs from UTF-8 byte length whenever the name contains non-ASCII characters, so the consistency check name.length() != tempByte.length throws AndrolibException.

Solutions

  1. Rename the offending resources to ASCII-only names in the source project (most robust fix).
  2. Ensure resource shrinking/obfuscation runs so names are replaced with short ASCII names before this writer executes.
  3. Patch StringBlock to compute the actual UTF-8 byte length and write multi-byte length fields (varint) instead of casting to byte.
  4. Locate the failing name from the message text and fix it in res/ values files.

Example fix

// before
stringBytes[offset++] = (byte) name.length();
// after
byte[] utf8 = name.getBytes(StandardCharsets.UTF_8);
stringBytes[offset++] = (byte) utf8.length;
stringBytes[offset++] = (byte) utf8.length;
Defensive patterns

Strategy: validation

Validate before calling

// Caller-side check before obfuscation
static boolean isAsciiSafe(String name) {
  return name.chars().allMatch(c -> c > 0 && c < 128);
}
// scan aapt2 output / res names: if (!isAsciiSafe(resName)) flagForRename(resName);

Try / catch

try { ... } catch (AndrolibException e) { if (e.getMessage().contains("UTF-8 length is different")) { /* report the offending resource name from the message and fail the build with a clear hint */ } else throw e; }

Prevention

When it happens

Trigger: writeSpecNameStringBlock with isUTF8 == true and a resource name whose UTF-8 byte length differs from its Java char count (non-ASCII or multi-byte characters, or names longer than 255 bytes cast into a byte).

Common situations: Apps with non-English resource entry names (Chinese, emoji, accented characters) in resources.arsc being obfuscated; also very long names exceeding 127/255-byte single-byte length encoding.

Related errors


AI-assisted analysis of shwenzhang/AndResGuard@e4df245d82 (2026-09-12). Data as JSON: /api/errors/79ac1a69c5175dfe. Report an issue: GitHub.

Appendix: source

Thrown at AndResGuard-core/src/main/java/com/tencent/mm/androlib/res/decoder/StringBlock.java:161

    byte[] stringBytes = new byte[size * 2];
    int offset = 0;
    int i = 0;
    curSpecNameToPos.clear();

    for (Iterator<String> it = specNames.keySet().iterator(); it.hasNext(); ) {
      stringOffsets[i] = offset;
      String name = it.next();
      for (String specName : specNames.get(name)) {
        // N res entry item point to one string constant
        curSpecNameToPos.put(specName, i);
      }
      if (isUTF8) {
        stringBytes[offset++] = (byte) name.length();
        stringBytes[offset++] = (byte) name.length();
        totalSize += 2;
        byte[] tempByte = name.getBytes(Charset.forName("UTF-8"));
        if (name.length() != tempByte.length) {
          throw new AndrolibException(String.format(
              "writeSpecNameStringBlock %s UTF-8 length is different name %d, tempByte %d\n",
              name,
              name.length(),
              tempByte.length
          ));
        }
        System.arraycopy(tempByte, 0, stringBytes, offset, tempByte.length);
        offset += name.length();
        stringBytes[offset++] = NULL;
        totalSize += name.length() + 1;
      } else {
        writeShort(stringBytes, offset, (short) name.length());
        offset += 2;
        totalSize += 2;
        byte[] tempByte = name.getBytes(Charset.forName("UTF-16LE"));
        if ((name.length() * 2) != tempByte.length) {
          throw new AndrolibException(String.format(
              "writeSpecNameStringBlock %s UTF-16LE length is different name %d, tempByte %d\n",

View on GitHub (pinned to e4df245d82)