{"record":{"id":"bb1497fb56a6910d","repo":"skylot/jadx","slug":"can-t-remove-ssa-var-still-in-use-count","errorCode":null,"errorMessage":"Can't remove SSA var: {}, still in use, count: {}, list:\n  {}","messagePattern":"Can't remove SSA var: (.+?), still in use, count: (.+?), list:\n  (.+?)","errorType":"exception","errorClass":"JadxRuntimeException","httpStatus":null,"severity":"error","filePath":"jadx-core/src/main/java/jadx/core/utils/InsnRemover.java","lineNumber":161,"sourceCode":"\t\t\tfor (RegisterArg arg : new ArrayList<>(ssaVar.getUseList())) {\n\t\t\t\tInsnNode parentInsn = arg.getParentInsn();\n\t\t\t\tif (parentInsn != null) {\n\t\t\t\t\t((PhiInsn) parentInsn).removeArg(arg);\n\t\t\t\t}\n\t\t\t}\n\t\t\tmth.removeSVar(ssaVar);\n\t\t\treturn;\n\t\t}\n\t\t// check if all usage only in not generated instructions\n\t\tif (allMatch(ssaVar.getUseList(),\n\t\t\t\targ -> arg.contains(AFlag.DONT_GENERATE) || InsnUtils.contains(arg.getParentInsn(), AFlag.DONT_GENERATE))) {\n\t\t\tfor (RegisterArg arg : ssaVar.getUseList()) {\n\t\t\t\targ.resetSSAVar();\n\t\t\t}\n\t\t\tmth.removeSVar(ssaVar);\n\t\t\treturn;\n\t\t}\n\t\tthrow new JadxRuntimeException(\"Can't remove SSA var: \" + ssaVar + \", still in use, count: \" + useCount\n\t\t\t\t+ \", list:\\n  \" + ssaVar.getUseList().stream()\n\t\t\t\t\t\t.map(arg -> arg + \" from \" + arg.getParentInsn())\n\t\t\t\t\t\t.collect(Collectors.joining(\"\\n  \")));\n\t}\n\n\tpublic static void unbindArgUsage(@Nullable MethodNode mth, InsnArg arg) {\n\t\tif (arg instanceof RegisterArg) {\n\t\t\tRegisterArg reg = (RegisterArg) arg;\n\t\t\tSSAVar sVar = reg.getSVar();\n\t\t\tif (sVar != null) {\n\t\t\t\tsVar.removeUse(reg);\n\t\t\t}\n\t\t} else if (arg instanceof InsnWrapArg) {\n\t\t\tInsnWrapArg wrap = (InsnWrapArg) arg;\n\t\t\tunbindInsn(mth, wrap.getWrapInsn());\n\t\t}\n\t}\n","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/skylot/jadx/blob/e738a26571d02919f01df40de93bc9a44dee4e18/jadx-core/src/main/java/jadx/core/utils/InsnRemover.java#L143-L179","documentation":"Thrown by InsnRemover.removeSsaVar when an SSA variable cannot be removed because it still has live uses: it has uses outside phi instructions and outside DONT_GENERATE instructions. removeSsaVar only unbinds vars whose remaining uses are all in PHIs or in instructions marked DONT_GENERATE; anything else means removing the var would orphan a live use, so it refuses.","triggerScenarios":"Calling InsnRemover.remove on an instruction whose result SSAVar is still used by another live (generated) instruction, or unbinding an SSA var before unbinding its consumers. The message lists every offending use with its parent instruction so you can see who still reads the var.","commonSituations":"Plugin/pass code that removes a defining instruction without first removing or re-routing its consumers; or an internal jadx pass that ordered removals incorrectly. The fix is almost always to unbind the consumers (InsnRemover.unbindArgUsage / unbindInsn) before removing the var.","solutions":["Unbind all uses of the var first: call InsnRemover.unbindInsn on each consumer, or InsnRemover.unbindAllArgs(mth, insn) on the consuming instructions, before removing the defining instruction.","Use the higher-level InsnRemover.remove(mth, block, insn) / unbindInsn(mth, insn) entry points rather than removeSsaVar directly - they handle consumer unbinding.","Inspect the use list in the message to find which live instruction still consumes the var and address it.","Update jadx; if this fires from a built-in pass, report the method."],"exampleFix":"// before - removing the def while uses remain\nInsnRemover.remove(mth, block, defInsn);\n// after - unbind consumers first, then remove\nInsnRemover.unbindAllArgs(mth, consumerInsn);\nInsnRemover.remove(mth, block, defInsn);","handlingStrategy":"validation","validationCode":"// confirm the var is removable before removing\nboolean removable = ssaVar.getUseCount() == 0\n    || ssaVar.getUseList().stream().allMatch(a ->\n        isInsnType(a.getParentInsn(), InsnType.PHI)\n        || a.contains(AFlag.DONT_GENERATE)\n        || InsnUtils.contains(a.getParentInsn(), AFlag.DONT_GENERATE));\nif (!removable) {\n    // unbind consumers first\n    InsnRemover.unbindAllArgs(mth, consumerInsn);\n}","typeGuard":null,"tryCatchPattern":"try {\n    InsnRemover.remove(mth, block, insn);\n} catch (JadxRuntimeException e) {\n    if (e.getMessage().startsWith(\"Can't remove SSA var\")) {\n        LOG.error(\"var still in use; uses:\\n{}\", e.getMessage());\n    } else { throw e; }\n}","preventionTips":["Always unbind consumers (InsnRemover.unbindAllArgs / unbindInsn) before removing a defining instruction.","Prefer the high-level InsnRemover.remove entry points over removeSsaVar.","Inspect the use list in the message to find the live consumer that still reads the var."],"tags":["decompiler","ssa","instructions","remover","invariant-violation"],"backgroundTag":null,"analyzedSha":"e738a26571d02919f01df40de93bc9a44dee4e18","analyzedAt":"2026-08-14T00:10:24.238Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}