Tencent/tinker · critical · IllegalStateException

Switch instruction at address/index 0x%x/%d does not refer t

Error message

Switch instruction at address/index 0x%x/%d does not refer to a payload instruction.

What it means

dexlib2 builder-stage validation error: a PACKED_SWITCH/SPARSE_SWITCH instruction does not point at a switch payload instruction ( BuilderSwitchPayload ). After following the target (skipping NOPs), the instruction found is not a payload, so the method cannot be safely rebuilt. Almost always caused by malformed dex content rather than by API misuse.

Source

Thrown at tinker-build/tinker-patch-lib/src/main/java/org/jf/dexlib2/builder/BuilderMutableMethodImplementation.java:482

        for (MethodLocation location : instructionList) {
            BuilderInstruction instruction = location.instruction;
            if (instruction != null) {
                switch (instruction.getOpcode()) {
                    case SPARSE_SWITCH:
                    case PACKED_SWITCH: {
                        MethodLocation targetLocation =
                                ((BuilderOffsetInstruction) instruction).getTarget().getLocation();
                        BuilderInstruction targetInstruction = targetLocation.instruction;
                        if (targetInstruction == null) {
                            throw new IllegalStateException(String.format("Switch instruction at address/index "
                                    + "0x%x/%d points to the end of the method.", location.codeAddress, location.index));
                        }

                        if (targetInstruction.getOpcode() == Opcode.NOP) {
                            targetInstruction = getFirstNonNop(targetLocation.index + 1);
                        }
                        if (targetInstruction == null || !(targetInstruction instanceof BuilderSwitchPayload)) {
                            throw new IllegalStateException(String.format("Switch instruction at address/index "
                                            + "0x%x/%d does not refer to a payload instruction.",
                                    location.codeAddress, location.index));
                        }
                        if ((instruction.opcode == Opcode.PACKED_SWITCH
                                && targetInstruction.getOpcode() != Opcode.PACKED_SWITCH_PAYLOAD)
                                || (instruction.opcode == Opcode.SPARSE_SWITCH
                                        && targetInstruction.getOpcode() != Opcode.SPARSE_SWITCH_PAYLOAD)) {
                            throw new IllegalStateException(String.format("Switch instruction at address/index "
                                            + "0x%x/%d refers to the wrong type of payload instruction.",
                                    location.codeAddress, location.index));
                        }

                        if (!payloadLocations.add(targetLocation)) {
                            throw new IllegalStateException("Multiple switch instructions refer to the same payload. "
                                    + "This is not currently supported. Please file a bug :)");
                        }

                        ((BuilderSwitchPayload) targetInstruction).referrer = location;

View on GitHub (pinned to 1b7ea02c23)

Solutions

  1. Confirm the old dex used at apply time is byte-identical to the one used at patch-generation time (compare signatures)
  2. Upgrade Tinker/dexlib2 to pick up fixes for unusual but legal payload layouts
  3. Remove the aggressive obfuscation rules that rewrite switch tables, then rebuild and re-diff
Defensive patterns

Strategy: try-catch

Try / catch

try {
    dexPatchApplier.executeAndSaveTo(out);
} catch (IllegalStateException e) {
    if (String.valueOf(e.getMessage()).contains("does not refer to a payload instruction")) {
        // treat as invalid dex/patch input: quarantine and regenerate
    } else { throw e; }
}

Prevention

When it happens

Trigger: Converting a method with a switch instruction whose target offset lands on a non-payload instruction (or on NOPs followed by a non-payload), during Tinker dex diff/patch apply when BuilderMutableMethodImplementation re-validates instructions.

Common situations: Obfuscated/protected dex with relocated or synthetic switch payloads; dex corrupted in transit (patch file partially downloaded); mismatch between the dex the patch was generated against and the dex it is applied to.

Related errors


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