{"record":{"id":"b6fcadf5dd7cabb9","repo":"skylot/jadx","slug":"anonymous-inner-class-unlimited-recursion-detected","errorCode":null,"errorMessage":"Anonymous inner class unlimited recursion detected. Convert class to inner: ","messagePattern":"Anonymous inner class unlimited recursion detected\\. Convert class to inner: ","errorType":"exception","errorClass":"CodegenException","httpStatus":null,"severity":"warning","filePath":"jadx-core/src/main/java/jadx/core/codegen/InsnGen.java","lineNumber":812,"sourceCode":"\t\tif (instArg.isThis()) {\n\t\t\treturn false;\n\t\t}\n\t\t// instance arg should be of an outer class type\n\t\tif (!instArg.getType().equals(ctrCls.getDeclaringClass().getType())) {\n\t\t\treturn false;\n\t\t}\n\t\taddArgDot(code, instArg);\n\t\t// can't use another dot, force short name of class\n\t\treturn true;\n\t}\n\n\tprivate void inlineAnonymousConstructor(ICodeWriter code, ClassNode cls, ConstructorInsn insn) throws CodegenException {\n\t\tcls.ensureProcessed();\n\t\tif (this.mth.getParentClass() == cls) {\n\t\t\tcls.remove(AType.ANONYMOUS_CLASS);\n\t\t\tcls.remove(AFlag.DONT_GENERATE);\n\t\t\tmth.getParentClass().getTopParentClass().add(AFlag.RESTART_CODEGEN);\n\t\t\tthrow new CodegenException(\"Anonymous inner class unlimited recursion detected.\"\n\t\t\t\t\t+ \" Convert class to inner: \" + cls.getClassInfo().getFullName());\n\t\t}\n\t\tArgType parent = cls.get(AType.ANONYMOUS_CLASS).getBaseType();\n\t\t// hide empty anonymous constructors\n\t\tfor (MethodNode ctor : cls.getMethods()) {\n\t\t\tif (ctor.contains(AFlag.ANONYMOUS_CONSTRUCTOR)\n\t\t\t\t\t&& RegionUtils.isEmpty(ctor.getRegion())) {\n\t\t\t\tctor.add(AFlag.DONT_GENERATE);\n\t\t\t}\n\t\t}\n\t\tcode.attachDefinition(cls);\n\t\tcode.add(\"new \");\n\t\tuseClass(code, parent);\n\t\tMethodNode callMth = mth.root().resolveMethod(insn.getCallMth());\n\t\tif (callMth != null) {\n\t\t\t// copy var names\n\t\t\tList<RegisterArg> mthArgs = callMth.getArgRegs();\n\t\t\tint argsCount = Math.min(insn.getArgsCount(), mthArgs.size());","sourceCodeStart":794,"sourceCodeEnd":830,"githubUrl":"https://github.com/skylot/jadx/blob/e738a26571d02919f01df40de93bc9a44dee4e18/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java#L794-L830","documentation":"Thrown by InsnGen.inlineAnonymousConstructor() when the anonymous class being inlined is the same class as the current method's parent class — meaning infinite recursion would occur if inlining proceeded. Rather than hanging, jadx converts the class from anonymous to a regular inner class (removes ANONYMOUS_CLASS and DONT_GENERATE flags), sets RESTART_CODEGEN to trigger a fresh codegen pass, and throws this CodegenException to unwind the current generation. This is a recovery mechanism, not a terminal error.","triggerScenarios":"An anonymous class whose constructor triggers inlining of itself, creating a cycle. This can happen with self-referential anonymous class patterns in obfuscated or generated code. The exception forces a restart where the class is treated as a normal inner class instead.","commonSituations":"Obfuscated code with circular anonymous class references. Kotlin lambda or inner class patterns that reference their own enclosing type during construction. The error message names the class being converted.","solutions":["This exception is expected recovery — it should be caught by wrapCodeGen which retries. If it surfaces as a user-visible error, the restart path itself also failed (see error 69).","If the restart also fails, report the class to jadx and use fallback mode.","No action needed if the decompilation succeeds after the restart — this is by design."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// This exception is caught internally by wrapCodeGen which triggers a restart.\n// If you see it surface, the restart also failed:\ntry {\n    codeGen.makeCode(cls);\n} catch (JadxRuntimeException e) {\n    if (e.getMessage().equals(\"Code generation error after restart\")) {\n        // The restart triggered by anonymous-class recursion also failed\n        Throwable cause = e.getCause();\n        logger.error(\"Anonymous class recursion recovery failed for: {}\",\n            cls.getClassInfo().getFullName(), cause);\n        args.setDecompilationMode(DecompilationMode.FALLBACK);\n    } else {\n        throw e;\n    }\n}","preventionTips":["Understand this exception is part of the recovery mechanism — it normally never surfaces.","If it does surface, the restart retry also failed; examine the cause chain.","Report the class with self-referential anonymous class patterns to jadx."],"tags":["codegen","anonymous-class","recursion","recovery","restart"],"backgroundTag":null,"analyzedSha":"e738a26571d02919f01df40de93bc9a44dee4e18","analyzedAt":"2026-08-14T00:10:24.238Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}