{"record":{"id":"431f4a957774149f","repo":"skylot/jadx","slug":"unexpected-arg-type-in-catch-block","errorCode":null,"errorMessage":"Unexpected arg type in catch block: ","messagePattern":"Unexpected arg type in catch block: ","errorType":"exception","errorClass":"JadxRuntimeException","httpStatus":null,"severity":"error","filePath":"jadx-core/src/main/java/jadx/core/codegen/RegionGen.java","lineNumber":376,"sourceCode":"\t\t\twhile (it.hasNext()) {\n\t\t\t\tcode.add(\" | \");\n\t\t\t\tuseClass(code, it.next());\n\t\t\t}\n\t\t}\n\t\tcode.add(' ');\n\t\tInsnArg arg = handler.getArg();\n\t\tif (arg == null) {\n\t\t\tcode.add(\"unknown\"); // throwing exception is too late at this point\n\t\t} else if (arg instanceof RegisterArg) {\n\t\t\tSSAVar ssaVar = ((RegisterArg) arg).getSVar();\n\t\t\tif (code.isMetadataSupported()) {\n\t\t\t\tcode.attachDefinition(VarNode.get(mth, ssaVar));\n\t\t\t}\n\t\t\tcode.add(mgen.getNameGen().assignArg(ssaVar.getCodeVar()));\n\t\t} else if (arg instanceof NamedArg) {\n\t\t\tcode.add(mgen.getNameGen().assignNamedArg((NamedArg) arg));\n\t\t} else {\n\t\t\tthrow new JadxRuntimeException(\"Unexpected arg type in catch block: \" + arg + \", class: \" + arg.getClass().getSimpleName());\n\t\t}\n\t\tcode.add(\") {\");\n\n\t\tInsnCodeOffset.attach(code, handler.getHandlerOffset());\n\t\tCodeGenUtils.addCodeComments(code, mth, handler.getHandlerBlock());\n\n\t\tmakeRegionIndent(code, region);\n\t}\n}\n","sourceCodeStart":358,"sourceCodeEnd":386,"githubUrl":"https://github.com/skylot/jadx/blob/e738a26571d02919f01df40de93bc9a44dee4e18/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java#L358-L386","documentation":"Thrown by RegionGen when emitting the exception variable of a catch block. The handler's argument must be either a RegisterArg (the normal case, backed by an SSA variable) or a NamedArg. If the exception arg is some other InsnArg subtype the codegen cannot name it and aborts. This is a late-stage codegen invariant failure.","triggerScenarios":"Decompiling bytecode whose exception handler argument was rewritten during type/name inference into an unexpected InsnArg subclass (e.g. an InsnArg wrap, a LiteralArg, or an uninitialised arg). Common with synthetic/obfuscated exception tables or after aggressive optimisation passes mutate handler args.","commonSituations":"Obfuscated apps with unusual exception handlers; malformed DEX; intermediate passes that swap a handler arg type; edge cases around multi-catch or TryWithResources desugaring. Rare on clean inputs.","solutions":["Update to the latest jadx; catch-block arg handling has been hardened over releases.","Isolate the failing class via logs and minimise a reproducer.","Inspect handler.getArg().getClass() at runtime (temporary logging) to see which InsnArg subtype leaked through, then trace the pass that created it.","Report to jadx with the reproducer and stack trace.","Workaround: skip decompilation of the affected class with class filters so the batch finishes."],"exampleFix":"// before\n} else if (arg instanceof NamedArg) {\n    code.add(mgen.getNameGen().assignNamedArg((NamedArg) arg));\n} else {\n    throw new JadxRuntimeException(\"Unexpected arg type in catch block: \" + arg + \", class: \" + arg.getClass().getSimpleName());\n}\n\n// after (defensive fallback name instead of aborting)\n} else {\n    LOG.warn(\"Unexpected arg type in catch block: {} ({}); using fallback name\", arg, arg.getClass().getSimpleName());\n    code.add(\"e\");\n}","handlingStrategy":"type-guard","validationCode":"InsnArg arg = handler.getArg();\nif (!(arg instanceof RegisterArg) && !(arg instanceof NamedArg)) {\n    LOG.warn(\"Unexpected catch arg type {} in {}, using fallback\", arg.getClass(), mth);\n}","typeGuard":"static boolean isSupportedCatchArg(InsnArg arg) {\n    return arg instanceof RegisterArg || arg instanceof NamedArg;\n}","tryCatchPattern":"try {\n    regionGen.makeCatchBlock(code, handler, region);\n} catch (JadxRuntimeException e) {\n    LOG.warn(\"Catch codegen failed in {}: {}\", mth, e.getMessage());\n    code.add(\"/* catch block omitted */\");\n}","preventionTips":["Wrap catch-block emission per method so one bad handler does not abort the class.","Report obfuscated exception tables that trigger this - they reveal decoder gaps.","Prefer decompiling per-class with isolation rather than whole-jar batch mode."],"tags":["codegen","exception-handling","decompiler-internal","invariant"],"backgroundTag":null,"analyzedSha":"e738a26571d02919f01df40de93bc9a44dee4e18","analyzedAt":"2026-08-14T00:10:24.238Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}