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
- Rename the offending resources to ASCII-only names in the source project (most robust fix).
- Ensure resource shrinking/obfuscation runs so names are replaced with short ASCII names before this writer executes.
- Patch StringBlock to compute the actual UTF-8 byte length and write multi-byte length fields (varint) instead of casting to byte.
- 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
- Enforce ASCII-only resource names via lint/custom check in the project.
- Enable resource obfuscation so original names are replaced with short ASCII ones.
- Avoid emoji and accented characters in resource entry names.
- CI: scan res/ filenames and value entry names for non-ASCII before release.
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
- writeTableNameStringBlock UTF-8 length is different name
- writeSpecNameStringBlock
- writeTableNameStringBlock UTF-16LE 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/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)