shwenzhang/AndResGuard · error · AndrolibException
writeSpecNameStringBlock
Error message
writeSpecNameStringBlock %s UTF-16LE length is different name %d, tempByte %d
What it means
The UTF-16LE branch of writeSpecNameStringBlock writes name.length() as the character count, then verifies that the actual UTF-16LE encoding uses exactly length*2 bytes. This fails when the name contains surrogate pairs (emoji, rare CJK), where Java's String.length() counts each surrogate separately but the UTF-16LE byte length still matches length*2 — or when the pool's declared encoding disagrees with the actual content, surfacing an encoding inconsistency.
Solutions
- Rename resources containing emoji/supplementary characters to plain ASCII identifiers.
- Enable resource name obfuscation so original names never reach this writer.
- Patch the check to count code points instead of chars when validating lengths.
- Inspect the name printed in the message and fix it in the res source files.
Defensive patterns
Strategy: validation
Validate before calling
static boolean hasSupplementaryChars(String name) {
return name.codePoints().anyMatch(cp -> cp > 0xFFFF);
}
// reject or rename resources where hasSupplementaryChars(resName) is true Try / catch
try { ... } catch (AndrolibException e) { if (e.getMessage().contains("UTF-16LE length is different")) { /* surface the resource name from the message; block release until renamed */ } else throw e; } Prevention
- Ban emoji/supplementary-plane characters in resource names by convention or lint rule.
- Prefer enabling AndResGuard name obfuscation to eliminate exotic names early.
- Review third-party library res/ contents for unusual names before integration.
- Run obfuscation in CI on every release candidate.
When it happens
Trigger: writeSpecNameStringBlock with isUTF8 == false and a resource name where name.getBytes(UTF_16LE).length != name.length()*2, typically due to surrogate-pair characters combined with the length-field encoding assumptions, or names longer than Short.MAX_VALUE.
Common situations: Resource names containing emoji or supplementary-plane characters; non-ASCII resource identifiers in apps localized with unusual names.
Related errors
- writeTableNameStringBlock UTF-16LE length is different name
- writeSpecNameStringBlock
- writeTableNameStringBlock UTF-8 length is different name
- Style data size is not multiple of 4
- writeSpecNameStringBlock styleOffsetCount != 0 …
AI-assisted analysis of shwenzhang/AndResGuard@e4df245d82 (2026-09-12).
Data as JSON: /api/errors/0a0abe421039d5eb.
Report an issue: GitHub.
Appendix: source
Thrown at AndResGuard-core/src/main/java/com/tencent/mm/androlib/res/decoder/StringBlock.java:178
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",
name,
name.length(),
tempByte.length
));
}
System.arraycopy(tempByte, 0, stringBytes, offset, tempByte.length);
offset += tempByte.length;
stringBytes[offset++] = NULL;
stringBytes[offset++] = NULL;
totalSize += tempByte.length + 2;
}
i++;
}
//要保证string size 是4的倍数,要补零
size = totalSize - stringsOffset;
if ((size % 4) != 0) {
int add = 4 - (size % 4);View on GitHub (pinned to e4df245d82)