skylot/jadx · error · JadxRuntimeException

Can't change package for inner class

Error message

Can't change package for inner class

What it means

Thrown by ClassInfo.changePkgAndName when the class is an inner class. Like error 92, this API refuses to repackage (or rename+repackage) an inner class because its identity is tied to its parent. The only difference from 92 is that this overload changes both package and short name together.

Source

Thrown at jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java:98

			fillAliasFullName(newAlias);
		}
		this.alias = newAlias;
	}

	public void changePkg(String aliasPkg) {
		if (isInner()) {
			throw new JadxRuntimeException("Can't change package for inner class: " + this);
		}
		if (!Objects.equals(getAliasPkg(), aliasPkg)) {
			ClassAliasInfo newAlias = new ClassAliasInfo(aliasPkg, getAliasShortName());
			fillAliasFullName(newAlias);
			this.alias = newAlias;
		}
	}

	public void changePkgAndName(String aliasPkg, String aliasShortName) {
		if (isInner()) {
			throw new JadxRuntimeException("Can't change package for inner class");
		}
		ClassAliasInfo newAlias = new ClassAliasInfo(aliasPkg, aliasShortName);
		fillAliasFullName(newAlias);
		this.alias = newAlias;
	}

	private void fillAliasFullName(ClassAliasInfo alias) {
		if (parentClass == null) {
			alias.setFullName(makeFullClsName(alias.getPkg(), alias.getShortName(), null, true, false));
		}
	}

	public String getAliasPkg() {
		if (isInner()) {
			return parentClass.getAliasPkg();
		}
		return alias == null ? getPackage() : alias.getPkg();
	}

View on GitHub (pinned to e738a26571)

Solutions

  1. Guard with isInner() before calling; route inner classes to their top-level parent for relocation.
  2. For inner classes that only need a rename (not a package change), use changeShortName instead, which is allowed for inner classes.
  3. In batch tools, separate the rename step (allowed for inner) from the repackage step (only top-level).
  4. Catch and skip inner classes in batch loops.

Example fix

// before
classInfo.changePkgAndName(newPkg, newName); // throws if inner

// after
if (classInfo.isInner()) {
    classInfo.changeShortName(newName); // rename only, package inherited
} else {
    classInfo.changePkgAndName(newPkg, newName);
}
Defensive patterns

Strategy: validation

Validate before calling

if (classInfo.isInner()) {
    classInfo.changeShortName(newName); // rename only
} else {
    classInfo.changePkgAndName(newPkg, newName);
}

Type guard

static boolean canChangePkgAndName(ClassInfo ci) {
    return !ci.isInner();
}

Try / catch

try {
    classInfo.changePkgAndName(newPkg, newName);
} catch (JadxRuntimeException e) {
    if (classInfo.isInner()) {
        classInfo.changeShortName(newName);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling changePkgAndName(aliasPkg, aliasShortName) on a ClassInfo with isInner() == true. Batch rename tools that combine rename + move and do not filter inner classes.

Common situations: Same as 92: deobfuscation scripts, GUI rename-and-move on nested classes, refactors operating over the full class graph.

Related errors


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