pxb1988/dex2jar · error · DexException
fail to load string @%08x
Error message
fail to load string %d@%08x
What it means
When resolving a string id, Mutf8.decode hit a UTFDataFormatException while decoding the MUTF-8 bytes of the string_data_item at the given offset. The reader wraps it in a DexException with the string id and hex offset so you can locate the bad entry. The dex's string table contains bytes that are not valid MUTF-8 or run past the end of the data section.
Solutions
- Re-obtain or re-extract the dex file — verify checksum/signature (the dex header stores both)
- Use the id@offset in the message to hexdump the failing string_data_item and check the bytes
- If you control the source, rebuild with d8/dx to regenerate a valid string table
- For robustness, patch Mutf8.decode usage to substitute invalid sequences instead of throwing if you must tolerate dirty inputs
Example fix
// before // java -jar dex2jar.jar broken.apk -> DexException: fail to load string 42@0001a2b0 // after // adb shell or unzip -t app.apk # verify archive integrity, re-extract classes.dex // then check header: head -c 12 classes.dex | xxd (magic + checksum)
Defensive patterns
Strategy: validation
Validate before calling
static boolean dexChecksumOk(byte[] dex) throws java.security.NoSuchAlgorithmException {
if (dex.length < 12) return false;
java.util.zip.Adler32 a = new java.util.zip.Adler32();
a.update(dex, 12, dex.length - 12);
int stored = (dex[8]&0xFF) | (dex[9]&0xFF)<<8 | (dex[10]&0xFF)<<16 | (dex[11]&0xFF)<<24;
return (int) a.getValue() == stored;
}
// reject files failing the Adler-32 checksum before DexFileReader touches the string table Try / catch
try {
new DexFileReader(file).accept(visitor);
} catch (DexException e) {
if (e.getMessage() != null && e.getMessage().startsWith("fail to load string")) {
throw new java.io.IOException("Corrupt DEX string table in " + file
+ " (" + e.getMessage() + "); re-extract or rebuild the dex", e);
}
throw e;
} Prevention
- Verify the dex Adler-32 checksum and SHA-1 signature from the header before parsing
- Re-extract APK entries rather than reusing possibly truncated dex copies
- Treat this as data corruption: id@offset in the message pinpoints the bad string for forensics
When it happens
Trigger: A string_ids/string_data entry whose modified-UTF-8 is invalid (e.g. raw surrogates encoded wrongly, truncated continuation bytes) or whose offset points outside valid data — corrupted dex, bad string_ids offsets, or non-dex bytes in the string section.
Common situations: Corrupted downloads/extractions of APKs; dex edited by string-rewriting tools that broke MUTF-8 encoding; malicious/packed apps with invalid string tables processed by dex2jar.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- Odex unsupported.
- Magic unsupported.
- Endian_tag unsupported
- Encountered RESTART_LOCAL on new v
- Invalid extended opcode encountered
AI-assisted analysis of pxb1988/dex2jar@b5bda4fb49 (2026-09-08).
Data as JSON: /api/errors/5e27884334ed1346.
Report an issue: GitHub.
Appendix: source
Thrown at dex-reader/src/main/java/com/googlecode/d2j/reader/DexFileReader.java:973
methoIdIn.position(id * 8);
int owner_idx = 0xFFFF & methoIdIn.getShort();
int proto_idx = 0xFFFF & methoIdIn.getShort();
int name_idx = methoIdIn.getInt();
return new Method(getType(owner_idx), getString(name_idx), getProto(proto_idx));
}
private String getString(int id) {
if (id == -1) {
return null;
}
int offset = stringIdIn.getInt(id * 4);
stringDataIn.position(offset);
int length = readULeb128i(stringDataIn);
try {
StringBuilder buff = new StringBuilder((int) (length * 1.5));
return Mutf8.decode(stringDataIn, buff);
} catch (UTFDataFormatException e) {
throw new DexException(e, "fail to load string %d@%08x", id, offset);
}
}
private String getType(int id) {
if (id == -1) {
return null;
}
return getString(typeIdIn.getInt(id * 4));
}
private int acceptField(ByteBuffer in, int lastIndex, DexClassVisitor dcv,
Map<Integer, Integer> fieldAnnotationPositions, Object value, int config) {
int diff = readULeb128i(in);
int field_access_flags = readULeb128i(in);
int field_id = lastIndex + diff;
Field field = getField(field_id);
// //////////////////////////////////////////////////////////////
DexFieldVisitor dfv = dcv.visitField(field_access_flags, field, value);
View on GitHub (pinned to b5bda4fb49)