apache/pulsar · error · IllegalArgumentException
Could not find sink config class
Error message
Could not find sink config class
What it means
Thrown by SinkConfigUtils.validateAndExtractDetails when the connector definition declares a sinkConfigClass that cannot be loaded via Class.forName using the sink function's classloader (ClassNotFoundException is rewrapped as IllegalArgumentException). The connector's custom config class is required to validate the sink's user-provided configs.
Source
Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SinkConfigUtils.java:752
}
if (newConfig.getTransformFunctionConfig() != null) {
mergedConfig.setTransformFunctionConfig(newConfig.getTransformFunctionConfig());
}
if (newConfig.getSourceSubscriptionPosition() != null) {
mergedConfig.setSourceSubscriptionPosition(newConfig.getSourceSubscriptionPosition());
}
return mergedConfig;
}
public static void validateSinkConfig(SinkConfig sinkConfig, ValidatableFunctionPackage sinkFunction) {
try {
ConnectorDefinition defn = sinkFunction.getFunctionMetaData(ConnectorDefinition.class);
if (defn != null && defn.getSinkConfigClass() != null) {
Class<?> configClass = Class.forName(defn.getSinkConfigClass(), true, sinkFunction.getClassLoader());
validateSinkConfig(sinkConfig, configClass);
}
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Could not find sink config class", e);
}
}
public static void validateSinkConfig(SinkConfig sinkConfig, Class<?> configClass) {
try {
Object configObject =
ObjectMapperFactory.getMapper().getObjectMapper()
.convertValue(sinkConfig.getConfigs(), configClass);
if (configObject != null) {
ConfigValidation.validateConfig(configObject);
}
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Could not validate sink config: " + e.getMessage());
}
}
}
View on GitHub (pinned to 820761864e)
Solutions
- Ensure the connector NAR contains the declared sinkConfigClass and matches the deployed version
- Correct the sinkConfigClass name in the connector definition (META-INF/services/connector yaml)
- Check the sinkFunction classloader includes the connector's jar; restart with the correct NAR
Example fix
// connector definition yaml // before sinkConfigClass: com.example.OldSinkConfig // after sinkConfigClass: com.example.MySinkConfig // class actually packaged in the NAR
Defensive patterns
Strategy: try-catch
Validate before calling
try {
Class.forName(sinkConfigClassFqcn, true, fnClassLoader);
} catch (ClassNotFoundException e) {
throw new IllegalStateException("Connector NAR is missing config class " + sinkConfigClassFqcn);
} Try / catch
try {
admin.sinks().updateSink(tenant, namespace, cfg, null);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("Could not find sink config class")) { /* redeploy correct connector NAR */ }
else throw e;
} Prevention
- Verify the connector NAR packages the class named in sinkConfigClass
- Keep connector definition yaml in sync with packaged class names across versions
- Test connector deployment in CI before production updates
When it happens
Trigger: Updating/submitting a sink backed by a connector whose ConnectorDefinition.getSinkConfigClass() names a class missing from the classpath/NAR, e.g. wrong NAR file version or class renamed in the connector.
Common situations: Custom connector NAR without the config class packaged; connector upgraded and config class renamed while old configs reference the old FQCN; typo in the sinkConfigClass declared in the connector's yaml.
Related errors
- Function class %s must be in class path
- Entry filter `${name}` cannot be loaded, see the broker logs
- Failed to load an authorization provider.
- Failed to compute configuration overrides
- Cannot load Pulsar Client Implementation:
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/96d2fef3322c80c1.
Report an issue: GitHub.