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.changePkg when attempting to change the package of a class that is an inner class (isInner() true). Package relocation is only valid for top-level classes; an inner class's package is derived from its parent, so changing it directly would break the parent/child relationship.

Source

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

		String aliasPkg = getAliasPkg();
		if (Objects.equals(name, aliasName) || StringUtils.isEmpty(aliasName)) {
			if (Objects.equals(getPackage(), aliasPkg)) {
				newAlias = null;
			} else {
				newAlias = new ClassAliasInfo(aliasPkg, name);
			}
		} else {
			newAlias = new ClassAliasInfo(aliasPkg, aliasName);
		}
		if (newAlias != null) {
			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) {

View on GitHub (pinned to e738a26571)

Solutions

  1. Check isInner() before calling changePkg; if true, relocate the enclosing top-level class instead (the inner follows its parent).
  2. For batch moves, iterate only top-level classes (parentClass == null) and let inner classes inherit.
  3. If you genuinely need to repackage an inner class, refactor it to a top-level class first (out of scope for this API).
  4. Catch JadxRuntimeException at the batch boundary to skip inner classes and continue.

Example fix

// before
classInfo.changePkg(newPkg); // throws if inner

// after
if (!classInfo.isInner()) {
    classInfo.changePkg(newPkg);
} else {
    // move the enclosing top-level class; inner follows
    ClassInfo top = classInfo.getTopParentClass();
    top.changePkg(newPkg);
}
Defensive patterns

Strategy: validation

Validate before calling

if (classInfo.isInner()) {
    // repackage the enclosing top-level class instead
    classInfo.getTopParentClass().changePkg(newPkg);
} else {
    classInfo.changePkg(newPkg);
}

Type guard

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

Try / catch

try {
    classInfo.changePkg(newPkg);
} catch (JadxRuntimeException e) {
    if (classInfo.isInner()) {
        classInfo.getTopParentClass().changePkg(newPkg);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling changePkg(aliasPkg) on a ClassInfo whose parentClass is non-null (an inner/nested class). Common in programmatic rename/batch-move operations that do not distinguish top-level from inner classes.

Common situations: Batch deobfuscation/rename scripts that move all classes to a new package; GUI 'move to package' invoked on an inner class; a refactor that reassigns packages recursively including nested classes.

Related errors


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