{"record":{"id":"655d4207fb7eadd7","repo":"pxb1988/dex2jar","slug":"stack-not-balanced","errorCode":null,"errorMessage":"stack not balanced","messagePattern":"stack not balanced","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"dex-translator/src/main/java/com/googlecode/d2j/converter/J2IRConverter.java","lineNumber":911,"sourceCode":"        if (parentCount[dst] > 1) {\n            for (int i = 0; i < src.getLocals(); i++) {\n                JvmValue p = src.getLocal(i);\n                JvmValue q = distFrame.getLocal(i);\n                if (p != null) {\n                    if (q == null) {\n                        q = new JvmValue(p.getSize());\n                        distFrame.setLocal(i, q);\n                    }\n                    relate(p, q);\n                }\n            }\n            if (src.getStackSize() > 0) {\n                if (distFrame.getStackSize() == 0) {\n                    for (int i = 0; i < src.getStackSize(); i++) {\n                        distFrame.push(new JvmValue(src.getStack(i).getSize()));\n                    }\n                } else if (distFrame.getStackSize() != src.getStackSize()) {\n                    throw new RuntimeException(\"stack not balanced\");\n                }\n                for (int i = 0; i < src.getStackSize(); i++) {\n                    JvmValue p = src.getStack(i);\n                    JvmValue q = distFrame.getStack(i);\n                    relate(p, q);\n                }\n            }\n        } else {\n            distFrame.init(src);\n        }\n    }\n\n    private void relate(JvmValue parent, JvmValue child) {\n        if (child.parent == null) {\n            child.parent = parent;\n        } else if (child.parent == parent) {\n            //\n        } else {","sourceCodeStart":893,"sourceCodeEnd":929,"githubUrl":"https://github.com/pxb1988/dex2jar/blob/b5bda4fb4935ae8b3869b422454ae3b3896c7bc1/dex-translator/src/main/java/com/googlecode/d2j/converter/J2IRConverter.java#L893-L929","documentation":"Thrown by J2IRConverter.merge() while abstractly interpreting JVM bytecode to build the data-flow frames used for Java-to-IR conversion. When two control-flow paths converge on a block that already has a frame, the operand stack depths must match; if the incoming stack size differs from the existing frame's stack size, the converter declares the stack unbalanced and aborts, because it cannot build a consistent single-assignment relation for the operands.","triggerScenarios":"Converting a Java class whose bytecode has a jump target reachable from paths with different operand-stack depths — typically hand-written, obfuscated, or bytecode-generated classes (ASM/bytecode manipulation tools) that leave values on the stack across branches; javac-compiled normal code does not trigger it.","commonSituations":"Translating obfuscated apps (proguard/branchy obfuscation), code produced by bytecode-generation frameworks, classes assembled with custom assemblers, or corrupted/class-file-version-mismatched bytecode fed into dex-translator's jar2dex pipeline.","solutions":["Identify the offending method/class from the surrounding stack trace and recompile it from source with a standard compiler so stack maps are balanced","Remove or soften the obfuscation (e.g. disable branch/control-flow obfuscation options) and retry the conversion","Ensure the input class file is not corrupted and matches a supported ASM class-file version (update dex-translator/ASM dependencies)","Patch J2IRConverter.merge to pad/trim stacks heuristically if you control the build and must accept such bytecode"],"exampleFix":"// before: converting obfuscated jar\ndexTranslator.convert(archiveIn, archiveOut);\n// after: pre-strip control-flow obfuscation, e.g. recompile source or run a deobfuscator first\njar2dex.convert(new File(\"input-obfuscated.jar\"), new File(\"out-dex.zip\")); // feed deobfuscated jar instead","handlingStrategy":"try-catch","validationCode":"// Prefer pre-verified input; check for branch obfuscation markers before conversion\nboolean risky = classFileWasObfuscated || !compiledByStandardCompiler;\nif (risky) { runDeobfuscatorOrRecompile(); }","typeGuard":null,"tryCatchPattern":"try {\n    dexTranslator.convert(inJar, outDex);\n} catch (RuntimeException e) {\n    if (\"stack not balanced\".equals(e.getMessage())) {\n        log.warn(\"Unbalanced-stack method; recompile or deobfuscate input\", e);\n        // fall back to a pre-desugared/deobfuscated artifact\n    } else throw e;\n}","preventionTips":["Feed only javac/ecj-compiled classes, not hand-assembled or obfuscated bytecode","Disable control-flow obfuscation for artifacts destined for jar2dex conversion","Pin compatible dex-translator and ASM versions","Log failing classes and rebuild them from source"],"tags":["java","bytecode","dataflow-analysis","dex-translator"],"backgroundTag":"internal-invariant-violation","analyzedSha":"b5bda4fb4935ae8b3869b422454ae3b3896c7bc1","analyzedAt":"2026-09-08T00:44:01.258Z","contentChangedAt":"2026-09-08T00:44:01.258Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}