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
- 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
- Rebuild/re-upload the archive so it actually contains the declared class and its dependencies
- If the connector was upgraded, use the new fully-qualified class name from its release notes
- 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
- Copy fully-qualified class names from the connector build output, never by hand
- After connector upgrades, regenerate configs with the new class names
- Run 'jar tf archive | grep <ClassName>' as a CI step before deployment
- Ensure shading configs don't strip connector classes from the final jar
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
- Source package doesn't contain the META-INF/services/pulsar-
- Failed to extract source class from archive
- Timestamp extractor class %s must be in class path
- %s class %s must be in class path
- Failed to load message payload processor class %sx
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/9675b6f12c32de80.
Report an issue: GitHub.