{"record":{"id":"4d9c9591195b1eb1","repo":"skylot/jadx","slug":"expected-to-find-fallthrough-terminus-for-handler","errorCode":null,"errorMessage":"Expected to find fallthrough terminus for handler {}","messagePattern":"Expected to find fallthrough terminus for handler (.+?)","errorType":"exception","errorClass":"JadxRuntimeException","httpStatus":null,"severity":"error","filePath":"jadx-core/src/main/java/jadx/core/dex/visitors/finaly/MarkFinallyVisitor.java","lineNumber":396,"sourceCode":"\t\tif (finallyScopeTerminus == null) {\n\t\t\treturn null;\n\t\t}\n\t\tMap<InsnNode, List<InsnNode>> matchingInsns = new HashMap<>();\n\t\tfor (TryEdge edge : tryInfo.handlerScopes.keySet()) {\n\t\t\tif (edge.isHandlerExit() && edge.getExceptionHandler() == tryInfo.finallyHandler) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tList<BlockNode> handlerBlocks = tryInfo.handlerScopes.get(edge);\n\t\t\tBlockNode scopeTerminus = null;\n\t\t\tfor (BlockNode edgeTerminusBlock : tryInfo.scopeTerminusGroups.keySet()) {\n\t\t\t\tList<TryEdge> edgesWithTerminus = tryInfo.scopeTerminusGroups.get(edgeTerminusBlock);\n\t\t\t\tif (edgesWithTerminus.contains(edge)) {\n\t\t\t\t\tscopeTerminus = edgeTerminusBlock;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (scopeTerminus == null) {\n\t\t\t\tthrow new JadxRuntimeException(\"Expected to find fallthrough terminus for handler \" + edge);\n\t\t\t}\n\t\t\tTraverserActivePathState comparatorState =\n\t\t\t\t\tnew TraverserActivePathState(mth, new SameInstructionsStrategyImpl(), finallyScopeTerminus,\n\t\t\t\t\t\t\tscopeTerminus, allHandlerBlocks, handlerBlocks);\n\t\t\tTraverserController controller = new TraverserController();\n\t\t\tList<TraverserActivePathState> pathResults;\n\t\t\ttry {\n\t\t\t\tpathResults = controller.process(comparatorState);\n\t\t\t} catch (TraverserException e) {\n\t\t\t\tLOG.error(\"Could not search for finally duplicate instructions in path\", e);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tSet<BlockNode> completeFinally = new HashSet<>();\n\t\t\tSet<BlockNode> completeCandidate = new HashSet<>();\n\t\t\tfor (TraverserActivePathState pathResult : pathResults) {\n\t\t\t\tfor (Pair<InsnNode> matchingInsnPair : pathResult.getMatchedInsns()) {\n\t\t\t\t\tInsnNode finallyInsn = matchingInsnPair.getFirst();\n\t\t\t\t\tInsnNode candidateInsn = matchingInsnPair.getSecond();","sourceCodeStart":378,"sourceCodeEnd":414,"githubUrl":"https://github.com/skylot/jadx/blob/e738a26571d02919f01df40de93bc9a44dee4e18/jadx-core/src/main/java/jadx/core/dex/visitors/finaly/MarkFinallyVisitor.java#L378-L414","documentation":"Thrown during finally block detection (MarkFinallyVisitor). For each try-catch handler edge, jadx searches the scope terminus groups to find where the try block's normal flow exits (the fallthrough terminus). If the handler edge is not found in any terminus group, the try-finally data structures are inconsistent and finally extraction cannot proceed.","triggerScenarios":"A TryEdge from tryInfo.handlerScopes has no matching entry in tryInfo.scopeTerminusGroups. Every handler edge is expected to appear in exactly one terminus group, but this edge is orphaned.","commonSituations":"Complex try-finally-catch combinations where the terminus grouping logic doesn't account for all handler edges; obfuscated exception handling that creates unusual try-finally nesting; methods with multiple nested finally blocks and overlapping exception ranges.","solutions":["Update jadx — finally analysis is an actively developed area with frequent edge-case fixes","Report the APK and method as a jadx issue with the full stack trace","Try disabling finally-related optimizations if available via command-line flags","Decompile the class individually to isolate the problematic method"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    jadxDecompiler.load();\n    jadxDecompiler.save();\n} catch (JadxRuntimeException e) {\n    if (e.getMessage().contains(\"Expected to find fallthrough terminus\")) {\n        LOG.warn(\"Finally block analysis inconsistency, skipping class\");\n        for (ClassNode cls : jadxDecompiler.getClasses()) {\n            try {\n                jadxDecompiler.decompileClass(cls);\n            } catch (JadxRuntimeException ex) {\n                LOG.warn(\"Skipped: {}\", cls.getFullName());\n            }\n        }\n    } else {\n        throw e;\n    }\n}","preventionTips":["Keep jadx updated — finally analysis is actively developed with frequent edge-case fixes","Report the APK as a jadx issue with the method that triggers it","Decompile classes individually to isolate the problematic method","Try different deobfuscation or debug-info settings that may change finally detection"],"tags":["finally-block","try-catch","exception-handling","decompiler"],"backgroundTag":null,"analyzedSha":"e738a26571d02919f01df40de93bc9a44dee4e18","analyzedAt":"2026-08-14T00:10:24.238Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}