apache/pulsar · error · IllegalArgumentException

Source class %s not found in class loader

Error message

Source class %s not found in class loader

What it means

After resolving the source class name, validateAndExtractDetails loads the type via sourceFunction.resolveType (ByteBuddy TypePool over the configured class loader). If the class does not exist in that loader, the resolution fails with NoSuchTypeException, rethrown as this IllegalArgumentException (with the class name interpolated) — the archive/classpath does not actually contain the declared class.

Source

Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SourceConfigUtils.java:310

        // thus we should try to find it class name in the NAR service definition
        if (sourceClassName == null) {
            ConnectorDefinition connectorDefinition = sourceFunction.getFunctionMetaData(ConnectorDefinition.class);
            if (connectorDefinition == null) {
                throw new IllegalArgumentException(
                        "Source package doesn't contain the META-INF/services/pulsar-io.yaml file.");
            }
            sourceClassName = connectorDefinition.getSourceClass();
            if (sourceClassName == null) {
                throw new IllegalArgumentException("Failed to extract source class from archive");
            }
        }

        // check if source implements the correct interfaces
        TypeDescription sourceClass;
        try {
            sourceClass = sourceFunction.resolveType(sourceClassName);
        } catch (TypePool.Resolution.NoSuchTypeException e) {
            throw new IllegalArgumentException(
              String.format("Source class %s not found in class loader", sourceClassName), e);
        }

        if (!(sourceClass.asErasure().isAssignableTo(Source.class) || sourceClass.asErasure()
                .isAssignableTo(BatchSource.class))) {
            throw new IllegalArgumentException(
                    String.format("Source class %s does not implement the correct interface",
                            sourceClass.getName()));
        }

        if (sourceClass.asErasure().isAssignableTo(BatchSource.class)) {
            if (sourceConfig.getBatchSourceConfig() != null) {
                validateBatchSourceConfig(sourceConfig.getBatchSourceConfig());
            } else {
                throw new IllegalArgumentException(
                  String.format("Source class %s implements %s but batch source source config is not specified",
                    sourceClass.getName(), BatchSource.class.getName()));
            }

View on GitHub (pinned to 820761864e)

Solutions

  1. Verify the exact class name inside the archive (unzip and javap / jar tf) and fix sourceConfig.setClassName(...) or the pulsar-io.yaml sourceClass to match
  2. Rebuild/re-upload the archive so it actually contains the declared class and its dependencies
  3. If the connector was upgraded, use the new fully-qualified class name from its release notes
  4. Check the NAR includes dependency jars (extraDeps) needed by the class

Example fix

// before
cfg.setClassName("com.example.MySource"); // class moved packages in v2
// after
cfg.setClassName("com.example.sources.MySource");
Defensive patterns

Strategy: validation

Validate before calling

// Before submit, confirm the class exists in the archive:
try (java.util.zip.ZipFile zar = new java.util.zip.ZipFile(cfg.getArchive())) {
    String path = cfg.getClassName().replace('.', '/') + ".class";
    boolean found = zar.stream().anyMatch(e -> e.getName().endsWith(path));
    if (!found) throw new IllegalStateException("Class " + cfg.getClassName() + " not present in " + cfg.getArchive());
}

Try / catch

try {
    SourceConfigUtils.validateAndExtractDetails(cfg, pkg, true);
} catch (IllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().contains("not found in class loader")) {
        // fix the class name or re-upload an archive that contains the class
    }
}

Prevention

When it happens

Trigger: className (explicit or extracted from pulsar-io.yaml) references a class absent from the uploaded archive or its dependencies — wrong package spelling, class renamed in a newer connector version, or missing dependency jar in the NAR.

Common situations: Refactoring a connector and forgetting to update sourceClass/className; uploading an old archive after upgrading the config; typos in fully-qualified class names; shading that strips the class from the final jar.

Related errors


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