skylot/jadx · error · JadxRuntimeException

Init of enum field '{}' uses external variables

Error message

Init of enum field '{}' uses external variables

What it means

Thrown by EnumVisitor when processing an enum constant's constructor call and finding that the constructor arguments reference register variables that cannot be inlined (inlineExternalRegs returns null). Enum constant initialisation should use only constant/literal values; references to external registers indicate the enum's $VALUES or <clinit> uses computed values that jadx cannot statically resolve.

Source

Thrown at jadx-core/src/main/java/jadx/core/dex/visitors/EnumVisitor.java:485

			return null;
		}
		// usually constructor signature is '<init>(Ljava/lang/String;I)V'
		// sometimes one or both args can be inlined or omitted
		String nameStr = null;
		if (co.getArgsCount() == 0) {
			ConstructorInsn ctrInsn = searchEnumSuperCtrInsn(ctrMth);
			if (ctrInsn != null && ctrInsn.getArgsCount() != 0) {
				nameStr = getConstString(ctrMth.root(), ctrInsn.getArg(0));
			}
		} else {
			nameStr = getConstString(cls.root(), co.getArg(0));
			// verify and try to inline additional constructor args
			List<RegisterArg> regs = new ArrayList<>();
			co.getRegisterArgs(regs);
			if (!regs.isEmpty()) {
				ConstructorInsn replacedCo = inlineExternalRegs(data, co);
				if (replacedCo == null) {
					throw new JadxRuntimeException("Init of enum field '" + enumFieldNode.getName() + "' uses external variables");
				}
				data.toRemove.add(co);
				co = replacedCo;
			}
		}
		return new EnumField(enumFieldNode, co, nameStr);
	}

	private @Nullable ConstructorInsn searchEnumSuperCtrInsn(MethodNode ctrMth) {
		for (BlockNode block : ctrMth.getBasicBlocks()) {
			for (InsnNode insn : block.getInstructions()) {
				if (insn.getType() == InsnType.CONSTRUCTOR) {
					ConstructorInsn ctrCall = (ConstructorInsn) insn;
					if (ctrCall.isSuper()
							&& ctrCall.getArgsCount() != 0
							&& ctrCall.getCallMth().getRawFullId().equals(ENUM_SUPER_CONSTRUCTOR_ID)) {
						return ctrCall;
					}

View on GitHub (pinned to e738a26571)

Solutions

  1. Upgrade jadx — enum-handling heuristics improve with each release.
  2. Catch JadxRuntimeException per class and skip the enum, allowing other classes to decompile.
  3. Report the issue with the enum class name and field name from the error message.
  4. Try alternative decompiler settings or tools for the specific class.
Defensive patterns

Strategy: try-catch

Try / catch

try {
    javaClass.decompile();
} catch (JadxRuntimeException e) {
    LOG.warn("Enum init with external vars in {}: {}", javaClass.getName(), e.getMessage());
}

Prevention

When it happens

Trigger: During enum class processing, a ConstructorInsn (co) for an enum field has register args (co.getRegisterArgs(regs) is non-empty). inlineExternalRegs(data, co) is called to resolve them but returns null — the registers reference values from outside the static initialiser that cannot be folded into constants.

Common situations: Enums in obfuscated code where the compiler or obfuscator generates complex <clinit> logic with shared registers. Also seen when an enum's constructor arguments are computed at runtime rather than being literals. Standard enum patterns (enum E { A, B }) work fine.

Related errors


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