apache/dubbo · error · IllegalArgumentException

non-public interfaces from different packages

Error message

non-public interfaces from different packages

What it means

Thrown by Proxy.buildProxyClass when one or more interfaces are non-public and their package differs from that of ics[0]. The generated proxy class is placed in the package of the first interface so it can access package-private interfaces; a non-public interface from a different package cannot be implemented from there, so Dubbo aborts with IllegalArgumentException.

Source

Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java:133

        return sb.toString();
    }

    private static Class<?> buildProxyClass(ClassLoader cl, Class<?>[] ics, ProtectionDomain domain) {
        ClassGenerator ccp = null;
        try {
            ccp = ClassGenerator.newInstance(cl);

            Set<String> worked = new HashSet<>();
            List<Method> methods = new ArrayList<>();

            String pkg = ics[0].getPackage().getName();
            Class<?> neighbor = ics[0];

            for (Class<?> ic : ics) {
                String npkg = ic.getPackage().getName();
                if (!Modifier.isPublic(ic.getModifiers())) {
                    if (!pkg.equals(npkg)) {
                        throw new IllegalArgumentException("non-public interfaces from different packages");
                    }
                }

                ccp.addInterface(ic);

                for (Method method : ic.getMethods()) {
                    String desc = ReflectUtils.getDesc(method);
                    if (worked.contains(desc) || Modifier.isStatic(method.getModifiers())) {
                        continue;
                    }
                    worked.add(desc);

                    int ix = methods.size();
                    Class<?> rt = method.getReturnType();
                    Class<?>[] pts = method.getParameterTypes();

                    StringBuilder code = new StringBuilder("Object[] args = new Object[")
                            .append(pts.length)

View on GitHub (pinned to 3a3043227f)

Solutions

  1. Make all interfaces passed to getProxy public.
  2. If some must stay package-private, keep them all in the same package as ics[0].
  3. Order the array so ics[0] is in the same package as every other non-public interface (only helps if all non-public share one package).

Example fix

// before
package a.b; interface InternalA {} // package-private
package c.d; public interface PublicB {}
Proxy.getProxy(InternalA.class, PublicB.class);

// after
package a.b; public interface InternalA {} // promote to public
Defensive patterns

Strategy: validation

Validate before calling

String pkg0 = ics[0].getPackageName();
for (Class<?> ic : ics) {
    if (!Modifier.isPublic(ic.getModifiers()) && !ic.getPackageName().equals(pkg0)) {
        throw new IllegalArgumentException("non-public interface " + ic + " from a different package");
    }
}

Prevention

When it happens

Trigger: Proxy.getProxy(ics) where ics mixes package-private interfaces from package X with a first interface (or other non-public interface) from package Y.

Common situations: Internal SPI interfaces that are not public and originate from different modules/packages; combining a public API interface with a package-private extension interface from another package.

Related errors


AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14). Data as JSON: /api/errors/077bb3620939528d. Report an issue: GitHub.