skylot/jadx · error · JadxRuntimeException

Unreachable block: {}

Error message

Unreachable block: {}

What it means

Thrown during block processing when a basic block has no predecessors and is not the method entry block. Jadx first attempts to explain it as a known synthetic pattern (EXC_SPLIT_CROSS), but if that fix doesn't apply, the block is genuinely orphaned and the CFG is inconsistent.

Source

Thrown at jadx-core/src/main/java/jadx/core/dex/visitors/blocks/BlockProcessor.java:143

	static void updateCleanSuccessors(MethodNode mth) {
		mth.getBasicBlocks().forEach(BlockNode::updateCleanSuccessors);
	}

	private static void checkForUnreachableBlocks(MethodNode mth) {
		while (true) {
			boolean fixed = false;
			for (BlockNode block : mth.getBasicBlocks()) {
				if (block.getPredecessors().isEmpty() && block != mth.getEnterBlock()) {
					// Sometimes a split cross block will have all it's predecessors moved elsewhere after it's been
					// created. This is usually detected at the time of it's creation, but in certain edge cases it
					// is difficult to do so. In those cases it will be cleanly removed here, along with the associated
					// bottom splitter.
					if (block.contains(AType.EXC_SPLIT_CROSS) && fixUnreachableSplitCross(mth, block)) {
						mth.addInfoComment("Removed unreachable split cross block " + block);
						fixed = true;
						break;
					}
					throw new JadxRuntimeException("Unreachable block: " + block);
				}
			}
			if (!fixed) {
				break;
			}
		}
	}

	/**
	 * Attempts to remove an unreachable synthetic split cross block that has been added previously,
	 * along with the associated bottom splitter.
	 *
	 * @param mth        the method containing the unreachable block
	 * @param splitCross the unreachable block
	 * @return true if the operation was successful, false if a precondition was not satisfied and no
	 *         changes were made.
	 */
	private static boolean fixUnreachableSplitCross(MethodNode mth, BlockNode splitCross) {

View on GitHub (pinned to e738a26571)

Solutions

  1. Update jadx — unreachable block handling is frequently patched
  2. Report the failing method and APK as a jadx issue
  3. Try with different deobfuscation settings that may affect block structure
  4. Decompile the class individually to isolate which method triggers it
Defensive patterns

Strategy: try-catch

Try / catch

try {
    jadxDecompiler.load();
    jadxDecompiler.save();
} catch (JadxRuntimeException e) {
    if (e.getMessage().contains("Unreachable block")) {
        LOG.warn("Unreachable block in CFG, skipping class");
        for (ClassNode cls : jadxDecompiler.getClasses()) {
            try {
                jadxDecompiler.decompileClass(cls);
            } catch (JadxRuntimeException ex) {
                LOG.warn("Skipped: {}", cls.getFullName());
            }
        }
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: After block splitting and initial processing, a BlockNode with empty predecessors and != enterBlock survives. fixUnreachableSplitCross returns false, meaning the block is not a removable synthetic split-cross artifact.

Common situations: Bugs in block-splitting or block-processing passes that leave orphaned blocks; unusual branch or jump patterns from obfuscators that create unreachable code islands; dead code not properly removed by earlier cleanup passes.

Related errors


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