Tencent/tinker · error · DexException
invalid LEB128 sequence
Error message
invalid LEB128 sequence
What it means
Thrown by Leb128.readSignedLeb128 when a signed LEB128 varint still has its continuation bit (0x80) set after 5 bytes. LEB128 encodes at most 32 bits in 5 groups of 7 bits (35 bits, but a 32-bit int needs ≤5); a 6th continuation means the stream is not a valid LEB128 encoding of an int.
Source
Thrown at third-party/aosp-dexutils/src/main/java/com/tencent/tinker/android/dex/Leb128.java:99
/**
* Reads an signed integer from {@code in}.
*/
public static int readSignedLeb128(ByteInput in) {
int result = 0;
int cur;
int count = 0;
int signBits = -1;
do {
cur = in.readByte() & 0xff;
result |= (cur & 0x7f) << (count * 7);
signBits <<= 7;
count++;
} while (((cur & 0x80) == 0x80) && count < 5);
if ((cur & 0x80) == 0x80) {
throw new DexException("invalid LEB128 sequence");
}
// Sign extend if appropriate
if (((signBits >> 1) & result) != 0) {
result |= signBits;
}
return result;
}
/**
* Reads an unsigned leb128 integer from {@code in}.
*/
public static int readUnsignedLeb128(ByteInput in) {
int result = 0;
int cur;
int count = 0;
View on GitHub (pinned to 1b7ea02c23)
Solutions
- Validate the dex before parsing (checksum + SHA-1 signature in the header, or dexdump) to rule out corruption.
- Audit any custom writer that produced the input to ensure it emits canonical, ≤5-byte LEB128.
- If reading a structured region, re-derive the start offset — an off-by-N start makes every subsequent varint invalid.
Defensive patterns
Strategy: try-catch
Try / catch
try { int v = Leb128.readSignedLeb128(in); } catch (DexException e) { throw new CorruptDexException(dexName, offset, e); } Prevention
- Checksum/SHA-1 validate dexes before deep parsing so corruption surfaces as an integrity error, not a varint error.
- If you write dexes, assert canonical LEB128 length (<=5 bytes) in your own writer's tests.
When it happens
Trigger: Parsing string_ids/type list sizes, ULEB128 fields in class_def, or any signed varint field from a buffer whose position is wrong (usually 1+ bytes off), or from a corrupt/truncated dex where what follows is payload, not a varint.
Common situations: Misaligned reads after a partial skip; dex files truncated by a bad copy or OTA patch; hand-built dex writers emitting >5-byte (over-long, non-canonical) LEB128 encodings that AOSP rejects.
Related errors
- Unexpected type: ${type}
- bad second byte
- bad second or third byte
- bad byte
- Declared length ${expectedLength} doesn't match decoded leng
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/61120ef1f6180344.
Report an issue: GitHub.