skylot/jadx · error · JadxRuntimeException

Can't remove SSA var: {}, still in use, count: {}, list: {

Error message

Can't remove SSA var: {}, still in use, count: {}, list:
  {}

What it means

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.

Source

Thrown at jadx-core/src/main/java/jadx/core/utils/InsnRemover.java:161

			for (RegisterArg arg : new ArrayList<>(ssaVar.getUseList())) {
				InsnNode parentInsn = arg.getParentInsn();
				if (parentInsn != null) {
					((PhiInsn) parentInsn).removeArg(arg);
				}
			}
			mth.removeSVar(ssaVar);
			return;
		}
		// check if all usage only in not generated instructions
		if (allMatch(ssaVar.getUseList(),
				arg -> arg.contains(AFlag.DONT_GENERATE) || InsnUtils.contains(arg.getParentInsn(), AFlag.DONT_GENERATE))) {
			for (RegisterArg arg : ssaVar.getUseList()) {
				arg.resetSSAVar();
			}
			mth.removeSVar(ssaVar);
			return;
		}
		throw new JadxRuntimeException("Can't remove SSA var: " + ssaVar + ", still in use, count: " + useCount
				+ ", list:\n  " + ssaVar.getUseList().stream()
						.map(arg -> arg + " from " + arg.getParentInsn())
						.collect(Collectors.joining("\n  ")));
	}

	public static void unbindArgUsage(@Nullable MethodNode mth, InsnArg arg) {
		if (arg instanceof RegisterArg) {
			RegisterArg reg = (RegisterArg) arg;
			SSAVar sVar = reg.getSVar();
			if (sVar != null) {
				sVar.removeUse(reg);
			}
		} else if (arg instanceof InsnWrapArg) {
			InsnWrapArg wrap = (InsnWrapArg) arg;
			unbindInsn(mth, wrap.getWrapInsn());
		}
	}

View on GitHub (pinned to e738a26571)

Solutions

  1. 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.
  2. Use the higher-level InsnRemover.remove(mth, block, insn) / unbindInsn(mth, insn) entry points rather than removeSsaVar directly - they handle consumer unbinding.
  3. Inspect the use list in the message to find which live instruction still consumes the var and address it.
  4. Update jadx; if this fires from a built-in pass, report the method.

Example fix

// before - removing the def while uses remain
InsnRemover.remove(mth, block, defInsn);
// after - unbind consumers first, then remove
InsnRemover.unbindAllArgs(mth, consumerInsn);
InsnRemover.remove(mth, block, defInsn);
Defensive patterns

Strategy: validation

Validate before calling

// confirm the var is removable before removing
boolean removable = ssaVar.getUseCount() == 0
    || ssaVar.getUseList().stream().allMatch(a ->
        isInsnType(a.getParentInsn(), InsnType.PHI)
        || a.contains(AFlag.DONT_GENERATE)
        || InsnUtils.contains(a.getParentInsn(), AFlag.DONT_GENERATE));
if (!removable) {
    // unbind consumers first
    InsnRemover.unbindAllArgs(mth, consumerInsn);
}

Try / catch

try {
    InsnRemover.remove(mth, block, insn);
} catch (JadxRuntimeException e) {
    if (e.getMessage().startsWith("Can't remove SSA var")) {
        LOG.error("var still in use; uses:\n{}", e.getMessage());
    } else { throw e; }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of skylot/jadx@e738a26571 (2026-08-14). Data as JSON: /api/errors/bb1497fb56a6910d. Report an issue: GitHub.