Tencent/tinker · error · IOException

Bad isa num: {}

Error message

Bad isa num: {}

What it means

ShareOatUtil reads the instruction-set number at offset 12 of the oat header and indexes the InstructionSet enum with it. If the int is negative or >= InstructionSet.values().length it throws IOException("Bad isa num: <n>"). The value read is not a valid InstructionSet ordinal, meaning the oat header layout differs from what the parser assumes or the file is corrupt.

Source

Thrown at tinker-android/tinker-android-loader/src/main/java/com/tencent/tinker/loader/shareutil/ShareOatUtil.java:100

            try {
                Integer.parseInt(oatVersion);
            } catch (NumberFormatException e) {
                throw new IOException("Bad oat version: " + oatVersion);
            }

            ByteBuffer buffer = ByteBuffer.allocate(128);
            buffer.order(elfFile.getDataOrder());
            // TODO This is a risk point, since each oat version may use a different offset.
            // So far it's ok. Perhaps we should use oatVersionNum to judge the right offset in
            // the future.
            final int isaNumOffsetFromOatBegin = 12;
            channel.position(roDataHdr.shOffset + isaNumOffsetFromOatBegin);
            buffer.limit(4);
            ShareElfFile.readUntilLimit(channel, buffer, "Failed to read isa num.");

            int isaNum = buffer.getInt();
            if (isaNum < 0 || isaNum >= InstructionSet.values().length) {
                throw new IOException("Bad isa num: " + isaNum);
            }

            switch (InstructionSet.values()[isaNum]) {
                case kArm:
                case kThumb2:
                    result = "arm";
                    break;
                case kArm64:
                    result = "arm64";
                    break;
                case kX86:
                    result = "x86";
                    break;
                case kX86_64:
                    result = "x86_64";
                    break;
                case kMips:
                    result = "mips";

View on GitHub (pinned to 1b7ea02c23)

Solutions

  1. Hex-inspect the oat header around offset 12 for the device's ART version and confirm the field is where the parser expects.
  2. Use getCurrentInstructionSet() (ABI-based) as a fallback when oat parsing throws.
  3. Upgrade Tinker for newer Android support.
  4. Delete the odex to force regeneration, then retry.
Defensive patterns

Strategy: fallback

Try / catch

try {
    isa = ShareOatUtil.getOatFileInstructionSet(odexFile);
} catch (IOException ioe) {
    // 'Bad isa num': header layout mismatch, fall back to ABI-derived ISA
    isa = ShareTinkerInternals.getCurrentInstructionSet();
}

Prevention

When it happens

Trigger: getOatFileInstructionSet where bytes at rodata offset 12 decode to an out-of-range int — oat version with different header layout (the code's TODO notes the offset risk), or a corrupted odex.

Common situations: Newer oat versions changing the isa field offset; unusual ABIs; corrupted odex produced or modified during OTA.

Related errors


AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14). Data as JSON: /api/errors/989b2ec9801b4e4a. Report an issue: GitHub.