apache/pulsar · error · IOException
The '%s' connector does not provide a source implementation
Error message
The '%s' connector does not provide a source implementation
What it means
ConnectorUtils.getIOSourceClass extracts the Pulsar IO Source class from a NAR connector archive. After parsing the connector's META-INF definition, if the sourceClass field is empty, the archive does not declare a source implementation, so an IOException is thrown because a Source cannot be built from this connector.
Source
Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/io/ConnectorUtils.java:71
@UtilityClass
@CustomLog
public class ConnectorUtils {
/**
* Computes a SHA-256 digest of a file as lower-case hex (for connector archive identity on reload).
*/
public static String computeArchiveChecksumHex(Path path) throws IOException {
return HexFormat.of().formatHex(FileUtils.calculateSha256sum(path.toAbsolutePath().normalize().toFile()));
}
/**
* Extract the Pulsar IO Source class from a connector archive.
*/
public static String getIOSourceClass(NarClassLoader narClassLoader) throws IOException {
ConnectorDefinition conf = getConnectorDefinition(narClassLoader);
if (StringUtils.isEmpty(conf.getSourceClass())) {
throw new IOException(
String.format("The '%s' connector does not provide a source implementation", conf.getName()));
}
try {
// Try to load source class and check it implements Source interface
Class<?> sourceClass = narClassLoader.loadClass(conf.getSourceClass());
if (!(Source.class.isAssignableFrom(sourceClass) || BatchSource.class.isAssignableFrom(sourceClass))) {
throw new IOException(String.format("Class %s does not implement interface %s or %s",
conf.getSourceClass(), Source.class.getName(), BatchSource.class.getName()));
}
} catch (Throwable t) {
Exceptions.rethrowIOException(t);
}
return conf.getSourceClass();
}
/**View on GitHub (pinned to 820761864e)
Solutions
- Use a connector NAR that actually implements a Source (check the connector's docs for source/sink support)
- Add the sourceClass entry to the connector's definition metadata and rebuild the NAR
- Verify the archive with getConnectorDefinition() before use and confirm getSourceClass() is non-empty
Example fix
// before: using a sink-only archive
String cls = ConnectorUtils.getIOSourceClass(loader); // throws
// after: check first
ConnectorDefinition def = ConnectorUtils.getConnectorDefinition(loader);
if (StringUtils.isNotEmpty(def.getSourceClass())) {
String cls = ConnectorUtils.getIOSourceClass(loader);
} Defensive patterns
Strategy: validation
Validate before calling
ConnectorDefinition def = ConnectorUtils.getConnectorDefinition(narClassLoader);
if (def == null || StringUtils.isEmpty(def.getSourceClass())) {
throw new IllegalArgumentException("NAR is not a source connector: " + def.getName());
} Type guard
boolean isSourceConnector(ConnectorDefinition def) {
return def != null && StringUtils.isNotEmpty(def.getSourceClass());
} Try / catch
try {
String src = ConnectorUtils.getIOSourceClass(loader);
} catch (IOException e) {
if (e.getMessage().contains("does not provide a source implementation")) {
// treat as sink-only connector, route accordingly
} else { throw e; }
} Prevention
- Keep separate NARs (or verify definitions) for source-only vs sink-only connectors
- Validate all uploaded connector NARs with getConnectorDefinition at deploy time
- Document which connectors are sink-only in your platform catalog
When it happens
Trigger: Calling getIOSourceClass(narClassLoader) on a connector NAR whose connector definition (META-INF/services/org.apache.pulsar.io.core.Connector or pulsar-io.yaml) declares no sourceClass, e.g. a sink-only connector.
Common situations: Deploying a sink-only connector (e.g. a JDBC/elasticsearch sink NAR) when creating a source; typos or missing fields in the connector metadata file; using a connector archive built from an older/empty definition.
Related errors
- The '%s' connector does not provide a sink implementation
- Invalid sink type '%s' -- Available sinks are: %s
- Sink package doesn't contain the META-INF/services/pulsar-io
- Failed to extract sink class from archive
- Connector is already closed
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/9a88d4154527a9a5.
Report an issue: GitHub.