apache/flink · error · ProgramInvocationException

The class %s must be public.

Error message

The class %s must be public.

What it means

Thrown by callMainMethod before attempting to look up the method, when the entry class's modifiers do not include public. A non-public class (package-private, protected, or private/nested) cannot be invoked as a main entry point even if it has a conforming main method.

Source

Thrown at flink-clients/src/main/java/org/apache/flink/client/program/PackagedProgram.java:331

            return false;
        } catch (Throwable t) {
            throw new RuntimeException(
                    "Could not look up the main(String[]) method from the class "
                            + entryClass.getName()
                            + ": "
                            + t.getMessage(),
                    t);
        }

        return Modifier.isStatic(mainMethod.getModifiers())
                && Modifier.isPublic(mainMethod.getModifiers());
    }

    private static void callMainMethod(Class<?> entryClass, String[] args)
            throws ProgramInvocationException {
        Method mainMethod;
        if (!Modifier.isPublic(entryClass.getModifiers())) {
            throw new ProgramInvocationException(
                    "The class " + entryClass.getName() + " must be public.");
        }

        try {
            mainMethod = entryClass.getMethod("main", String[].class);
        } catch (NoSuchMethodException e) {
            throw new ProgramInvocationException(
                    "The class " + entryClass.getName() + " has no main(String[]) method.");
        } catch (Throwable t) {
            throw new ProgramInvocationException(
                    "Could not look up the main(String[]) method from the class "
                            + entryClass.getName()
                            + ": "
                            + t.getMessage(),
                    t);
        }

        if (!Modifier.isStatic(mainMethod.getModifiers())) {

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Declare the entry class as 'public' (and top-level or public static nested).
  2. If it must be nested, make the outer class public and the nested class 'public static'.
  3. Rebuild the jar and resubmit, confirming the same class name resolves to the now-public class.

Example fix

// before
class MyJob { // package-private
    public static void main(String[] a) {}
}

// after
public class MyJob {
    public static void main(String[] a) {}
}
Defensive patterns

Strategy: validation

Validate before calling

if (!Modifier.isPublic(entryClass.getModifiers())) {
    throw new IllegalArgumentException(
        "Entry class " + entryClass.getName() + " must be public");
}

Try / catch

try {
    PackagedProgram.newBuilder().setEntryPointClassName(cls).setJarFile(jar).build();
} catch (ProgramInvocationException pie) {
    if (pie.getMessage().contains("must be public")) {
        // tell user to make the class public
    }
    throw pie;
}

Prevention

When it happens

Trigger: The entry point class is package-private or is a non-public nested class, but is referenced via --class or the manifest.

Common situations: Submitting a class that was never declared public (default access). Submitting an inner class (non-static or non-public) as the entry point. Code that 'worked in IDE' because the IDE bypassed access rules.

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/0ace40781110bcc7. Report an issue: GitHub.