LSPosed/LSPosed · error · IllegalArgumentException

${subClass} is not inherited from ${superClass}

Error message

${subClass} is not inherited from ${superClass}

What it means

newInstanceSpecial allocates an instance of subClass and runs the superclass constructor on it via invokespecial. For that to be legal, subClass must actually inherit from the constructor's declaring class; LSPosedContext checks superClass.isAssignableFrom(subClass) (line 272) and throws IllegalArgumentException naming both classes otherwise.

Source

Thrown at core/src/main/java/org/lsposed/lspd/impl/LSPosedContext.java:272

            throw new IllegalArgumentException("Cannot invoke special on static method: " + method);
        }
        return HookBridge.invokeSpecialMethod(method, getExecutableShorty(method), method.getDeclaringClass(), thisObject, args);
    }

    @NonNull
    @Override
    public <T> T newInstanceOrigin(@NonNull Constructor<T> constructor, Object... args) throws InvocationTargetException, IllegalAccessException, InstantiationException {
        var obj = HookBridge.allocateObject(constructor.getDeclaringClass());
        HookBridge.invokeOriginalMethod(constructor, obj, args);
        return obj;
    }

    @NonNull
    @Override
    public <T, U> U newInstanceSpecial(@NonNull Constructor<T> constructor, @NonNull Class<U> subClass, Object... args) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, InstantiationException {
        var superClass = constructor.getDeclaringClass();
        if (!superClass.isAssignableFrom(subClass)) {
            throw new IllegalArgumentException(subClass + " is not inherited from " + superClass);
        }
        var obj = HookBridge.allocateObject(subClass);
        HookBridge.invokeSpecialMethod(constructor, getExecutableShorty(constructor), superClass, obj, args);
        return obj;
    }

    @Override
    public void log(@NonNull String message) {
        Log.i(TAG, mPackageName + ": " + message);
    }

    @Override
    public void log(@NonNull String message, @NonNull Throwable throwable) {
        Log.e(TAG, mPackageName + ": " + message, throwable);
    }

    @Override
    public DexParser parseDex(@NonNull ByteBuffer dexData, boolean includeAnnotations) throws IOException {

View on GitHub (pinned to df74d83eb0)

Solutions

  1. Pass a class that genuinely extends constructor.getDeclaringClass()
  2. Derive the argument from the constructor itself if possible, or assert the relation before calling
  3. If you just want a normal instance of the declaring class, use newInstanceOrigin(constructor, args)

Example fix

// before
Object o = context.newInstanceSpecial(BaseCtor, UnrelatedClass.class, args);

// after
assert BaseCtor.getDeclaringClass().isAssignableFrom(ChildClass.class);
Object o = context.newInstanceSpecial(BaseCtor, ChildClass.class, args);
Defensive patterns

Strategy: validation

Validate before calling

Class<?> sup = constructor.getDeclaringClass();
if (!sup.isAssignableFrom(subClass)) {
    throw new IllegalArgumentException(subClass + " must extend " + sup);
}
return context.newInstanceSpecial(constructor, subClass, args);

Type guard

static boolean isValidSpecialTarget(Constructor<?> ctor, Class<?> sub) {
    return ctor.getDeclaringClass().isAssignableFrom(sub);
}

Prevention

When it happens

Trigger: Calling context.newInstanceSpecial(constructor, subClass, args) where subClass is not a subclass (or subinterface/array type) of constructor.getDeclaringClass().

Common situations: Passing an unrelated class or the declaring class itself when the constructor belongs to a different branch of the hierarchy; refactoring that moved the constructor's class so the old subClass argument no longer extends it.

Related errors


AI-assisted analysis of LSPosed/LSPosed@df74d83eb0 (2026-08-14). Data as JSON: /api/errors/0450f6b28145954a. Report an issue: GitHub.