skylot/jadx · error · JadxRuntimeException

Copy blocks tree failed. Missing block for connection: {}

Error message

Copy blocks tree failed. Missing block for connection: {}

What it means

Thrown when copying a block tree (used for method duplication in JSR resolution and inlining). The copy process builds a map from original blocks to new blocks, then reconnects successors. If a successor block has no entry in the map, the tree structure is incomplete and the copy cannot proceed.

Source

Thrown at jadx-core/src/main/java/jadx/core/dex/visitors/blocks/BlockSplitter.java:235

			BlockNode newBlock = startNewBlock(mth, block.getStartOffset());
			copyBlockData(block, newBlock);
			copyBlocks.add(newBlock);
			map.put(block, newBlock);
		}
		for (BlockNode block : blocks) {
			BlockNode newBlock = getNewBlock(block, map);
			for (BlockNode successor : block.getSuccessors()) {
				BlockNode newSuccessor = getNewBlock(successor, map);
				BlockSplitter.connect(newBlock, newSuccessor);
			}
		}
		return copyBlocks;
	}

	private static BlockNode getNewBlock(BlockNode block, Map<BlockNode, BlockNode> map) {
		BlockNode newBlock = map.get(block);
		if (newBlock == null) {
			throw new JadxRuntimeException("Copy blocks tree failed. Missing block for connection: " + block);
		}
		return newBlock;
	}

	static void replaceTarget(BlockNode source, BlockNode oldTarget, BlockNode newTarget) {
		InsnNode lastInsn = BlockUtils.getLastInsn(source);
		if (lastInsn instanceof TargetInsnNode) {
			((TargetInsnNode) lastInsn).replaceTargetBlock(oldTarget, newTarget);
		}
	}

	private static void setupConnectionsFromJumps(MethodNode mth, Map<Integer, BlockNode> blocksMap) {
		for (BlockNode block : mth.getBasicBlocks()) {
			for (InsnNode insn : block.getInstructions()) {
				List<JumpInfo> jumps = insn.getAll(AType.JUMP);
				for (JumpInfo jump : jumps) {
					BlockNode srcBlock = getBlock(jump.getSrc(), blocksMap);
					BlockNode thisBlock = getBlock(jump.getDest(), blocksMap);

View on GitHub (pinned to e738a26571)

Solutions

  1. Update jadx — block tree copy logic is periodically refined
  2. Report the APK and failing method as a jadx issue with the full stack trace
  3. Try with --no-inline-anonymous or similar flags that reduce code duplication
  4. Exclude the problematic class if the rest of the APK decompiles fine
Defensive patterns

Strategy: try-catch

Try / catch

try {
    jadxDecompiler.load();
    jadxDecompiler.save();
} catch (JadxRuntimeException e) {
    if (e.getMessage().contains("Copy blocks tree failed")) {
        LOG.warn("Block tree copy inconsistency, trying per-class decompilation");
        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: During copyBlocksTree, getNewBlock(successor, map) returns null because the successor BlockNode was not included in the initial map population. This means the source block graph has a successor that wasn't registered for copying.

Common situations: Internal inconsistency in the block graph during duplication; a block was added or modified between map creation and successor traversal; typically triggered during JSR/RET resolution or method inlining on complex control flow.

Related errors


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