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
- Update jadx — unreachable block handling is frequently patched
- Report the failing method and APK as a jadx issue
- Try with different deobfuscation settings that may affect block structure
- 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
- Keep jadx updated — unreachable block handling is frequently patched
- Report the APK as a jadx issue
- Decompile classes individually to isolate the problematic method
- Try different deobfuscation settings that may affect block structure
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
- Failed to find top block for try-catch from: {}
- Copy blocks tree failed. Missing block for connection: {}
- Try blocks wrapping queue limit reached! Please report as an
- Unexpected missing predecessor for block: {}
- Missing block: {}
AI-assisted analysis of skylot/jadx@e738a26571 (2026-08-14).
Data as JSON: /api/errors/0b4f30d1b4e2f49d.
Report an issue: GitHub.