apache/flink · critical · ClassNotFoundException

Class '%s' not found. Perhaps you forgot to add the module '

Error message

Class '%s' not found. Perhaps you forgot to add the module '%s' to the classpath?

What it means

Thrown by ComponentClassLoader.loadClass when a class cannot be found in the component classloader and the class's package prefix matches a known module association. The error enriches the raw ClassNotFoundException with a hint about which module likely provides the missing class.

Source

Thrown at flink-core/src/main/java/org/apache/flink/core/classloading/ComponentClassLoader.java:122

                    return loadClassFromComponentFirst(name, resolve);
                }
                if (isOwnerFirstClass(name)) {
                    return loadClassFromOwnerFirst(name, resolve);
                }

                // making this behavior configurable (component-only/component-first/owner-first)
                // would allow this class to subsume the FlinkUserCodeClassLoader (with an added
                // exception handler)
                return loadClassFromComponentOnly(name, resolve);
            } catch (ClassNotFoundException e) {
                // If we know the package of this class
                Optional<String> foundAssociatedModule =
                        knownPackagePrefixesModuleAssociation.entrySet().stream()
                                .filter(entry -> name.startsWith(entry.getKey()))
                                .map(Map.Entry::getValue)
                                .findFirst();
                if (foundAssociatedModule.isPresent()) {
                    throw new ClassNotFoundException(
                            String.format(
                                    "Class '%s' not found. Perhaps you forgot to add the module '%s' to the classpath?",
                                    name, foundAssociatedModule.get()),
                            e);
                }
                throw e;
            }
        }
    }

    private Class<?> resolveIfNeeded(final boolean resolve, final Class<?> loadedClass) {
        if (resolve) {
            resolveClass(loadedClass);
        }
        return loadedClass;
    }

    private boolean isOwnerFirstClass(final String name) {

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Add the named module JAR to the Flink lib directory or your job's classpath.
  2. Verify the module version matches your Flink distribution version.
  3. If the module should be present, check for classloader isolation issues or shaded dependency conflicts.

Example fix

# before: missing planner
# job fails with Class 'org.apache.flink.table.planner...' not found, module 'flink-table-planner-loader'

# after: add the JAR to lib
cp flink-table-planner-loader-*.jar $FLINK_HOME/lib/
Defensive patterns

Strategy: validation

Validate before calling

// Before launching, verify required module JARs are present
Path libDir = Paths.get(flinkHome, "lib");
List<String> required = List.of("flink-table-planner", "flink-clients");
for (String mod : required) {
    try (Stream<Path> files = Files.list(libDir)) {
        if (files.noneMatch(p -> p.getFileName().toString().startsWith(mod))) {
            throw new IllegalStateException("Missing module JAR: " + mod);
        }
    }
}

Try / catch

try {
    Class.forName(className);
} catch (ClassNotFoundException e) {
    if (e.getMessage().contains("forgot to add the module")) { /* add the named module JAR */ }
}

Prevention

When it happens

Trigger: A class whose package (e.g., org.apache.flink.table.*) is associated with a known module (e.g., flink-table) but that module's JAR is not on the classpath. The classloader tried component-only, owner, etc. and fell through to the catch block.

Common situations: Running Flink without the table planner JAR when executing SQL/Table API jobs. Missing connector JARs in the lib directory. Deploying a slim distribution that omits needed modules. Version mismatch where a module was renamed or split.

Related errors


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