apache/pulsar · error · RuntimeException

Class constructor throws exception

Error message

Class  constructor throws exception

What it means

createInstance() invokes the no-arg constructor via reflection; InvocationTargetException means the constructor body itself threw an exception, which Pulsar rethrows as RuntimeException("Class X constructor throws exception") with the original cause attached via getCause().

Source

Thrown at pulsar-functions/runtime-all/src/main/java/org/apache/pulsar/functions/instance/JavaInstanceMain.java:152

        try {
            theCls = Class.forName(userClassName, true, classLoader);
        } catch (ClassNotFoundException | NoClassDefFoundError cnfe) {
            throw new RuntimeException("Class " + userClassName + " must be in class path", cnfe);
        }
        Object result;
        try {
            Constructor<?> meth = theCls.getDeclaredConstructor();
            meth.setAccessible(true);

            result = meth.newInstance();
        } catch (InstantiationException ie) {
            throw new RuntimeException("User class must be concrete", ie);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException("Class " + userClassName + " doesn't have such method", e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Class " + userClassName + " must have a no-arg constructor", e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException("Class " + userClassName + " constructor throws exception", e);
        }
        return result;
    }

    public static ClassLoader loadJar(ClassLoader parent, File[] jars) throws MalformedURLException {
        URL[] urls = new URL[jars.length];
        for (int i = 0; i < jars.length; i++) {
            urls[i] = jars[i].toURI().toURL();
        }
        return new URLClassLoader(urls, parent);
    }

    public static boolean isBlank(String str) {
        int strLen;
        if (str != null && (strLen = str.length()) != 0) {
            for (int i = 0; i < strLen; ++i) {
                if (!Character.isWhitespace(str.charAt(i))) {
                    return false;

View on GitHub (pinned to 820761864e)

Solutions

  1. Inspect the cause chain (e.printStackTrace / logs) — the real error is inside InvocationTargetException.getCause().
  2. Move initialization out of the constructor into open()/initialize(Context) where failures are handled by the instance lifecycle.
  3. Make the constructor trivially safe; defer resource acquisition and config reading.
  4. Ensure any classes touched by the constructor are present in the function jar/classpath.

Example fix

// before
public MyFunction() { conn = DriverManager.getConnection(url); }
// after
public MyFunction() {}
public void open(Map config, FunctionContext ctx) { conn = DriverManager.getConnection(url); }
Defensive patterns

Strategy: try-catch

Validate before calling

// dry-run the constructor before submitting
Class<?> c = Class.forName(className);
c.getDeclaredConstructor().newInstance();

Type guard

null

Try / catch

try { Object f = JavaInstanceMain.createInstance(className, cl); } catch (RuntimeException e) { if (e.getMessage().contains("constructor throws exception")) { e.getCause().printStackTrace(); /* the real error */ } throw e; }

Prevention

When it happens

Trigger: The user function's no-arg constructor performs initialization that fails: reading a missing file/env var, connecting to an external service, throwing from static/instance initializers, or failing NPE in field initialization.

Common situations: Heavy work in constructors (connecting to DBs, reading configs) instead of open(); static initializer throwing; dependencies loaded in the constructor that aren't on the classpath ( NoClassDefFoundError wrapped as InvocationTargetException).

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/afdc39d549b6f5ed. Report an issue: GitHub.