skylot/jadx · error · JadxRuntimeException

Failed to decode insn: {}

Error message

Failed to decode insn: {}

What it means

Thrown when a SECOND instruction fails to decode within the same method. InsnDecoder.process() tolerates the first failure (records a soft JadxError on a NOP placeholder), but on a second failure it aborts method processing by re-throwing as JadxRuntimeException. This propagates up to MethodNode.load(), which catches it, reloads the method without code, and re-wraps as DecodeException.

Source

Thrown at jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java:57

	public InsnDecoder(MethodNode mthNode) {
		this.method = mthNode;
		this.root = method.root();
	}

	public InsnNode[] process(ICodeReader codeReader) {
		InsnNode[] instructions = new InsnNode[codeReader.getUnitsCount()];
		codeReader.visitInstructions(rawInsn -> {
			int offset = rawInsn.getOffset();
			InsnNode insn;
			try {
				rawInsn.decode();
				insn = decode(rawInsn);
			} catch (Exception e) {
				boolean mthWithErrors = method.contains(AType.JADX_ERROR);
				method.addError("Failed to decode insn: " + rawInsn, e);
				if (mthWithErrors) {
					// second error in this method => abort processing
					throw new JadxRuntimeException("Failed to decode insn: " + rawInsn, e);
				}
				insn = new InsnNode(InsnType.NOP, 0);
				insn.addAttr(AType.JADX_ERROR, new JadxError("decode failed: " + e.getMessage(), e));
			}
			insn.setOffset(offset);
			instructions[offset] = insn;
		});
		return instructions;
	}

	protected InsnNode decode(InsnData insn) throws DecodeException {
		switch (insn.getOpcode()) {
			case NOP:
				return new InsnNode(InsnType.NOP, 0);

			// move-result will be process in invoke and filled-new-array instructions
			case MOVE_RESULT:
				return insn(InsnType.MOVE_RESULT, InsnArg.reg(insn, 0, ArgType.UNKNOWN));

View on GitHub (pinned to e738a26571)

Solutions

  1. Upgrade JADX to the latest release — newer versions decode more opcode patterns and obfuscation tricks.
  2. Run jadx with --show-bad-code to emit partial output despite per-instruction decode failures.
  3. Re-extract the APK from a clean source to rule out download/transfer corruption.
  4. Report the class/method and full stack trace to the JADX issue tracker for the unhandled bytecode shape.
Defensive patterns

Strategy: try-catch

Try / catch

// Decompile class-by-class so one method's decode failure does not abort the whole run.
for (JavaClass cls : jadx.getClasses()) {
    try {
        String code = cls.getCode();
    } catch (JadxRuntimeException | DecodeException e) {
        log.warn("Decode failed for class {}, skipping", cls.getClassNode().getClassInfo(), e);
    }
}

Prevention

When it happens

Trigger: Decoding a DEX method whose bytecode contains two or more unparseable instructions. The first decode error sets AType.JADX_ERROR on the method (mthWithErrors check at line 53); the second hits the 'abort' branch at line 57.

Common situations: Heavily obfuscated APKs, DEX emitted by novel/buggy compilers or packers, truncated DEX code sections, or APKs targeting a newer Android API level whose opcode patterns the installed JADX release does not yet handle.

Understand the failure class

Related errors


AI-assisted analysis of skylot/jadx@e738a26571 (2026-08-14). Data as JSON: /api/errors/c44049350f36bdf3. Report an issue: GitHub.