apache/pulsar · error · IllegalArgumentException

Sink class %s not found

Error message

Sink class %s not found

What it means

Thrown by SinkConfigUtils.validateAndExtractDetails when the sink's class name (sinkClassName) cannot be resolved in the sink package's type pool via ByteBuddy's resolveType. The library validates that the configured sink class exists in the uploaded archive/NAR before creating a sink. It wraps TypePool.Resolution.NoSuchTypeException in an IllegalArgumentException.

Source

Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SinkConfigUtils.java:478

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

        // check if sink implements the correct interfaces
        TypeDefinition sinkClass;
        try {
            sinkClass = sinkFunction.resolveType(sinkClassName);
        } catch (TypePool.Resolution.NoSuchTypeException e) {
            throw new IllegalArgumentException(
                    String.format("Sink class %s not found", sinkClassName), e);
        }

        String functionClassName = sinkConfig.getTransformFunctionClassName();
        TypeDefinition typeArg;
        ValidatableFunctionPackage inputFunction;
        if (transformFunction != null) {
            // if function class name in sink config is not set, this should be a built-in function
            // thus we should try to find it class name in the NAR service definition
            if (functionClassName == null) {
                FunctionDefinition functionDefinition =
                        transformFunction.getFunctionMetaData(FunctionDefinition.class);
                if (functionDefinition == null) {
                    throw new IllegalArgumentException(
                            "Function package doesn't contain the META-INF/services/pulsar-io.yaml file.");
                }
                functionClassName = functionDefinition.getFunctionClass();
                if (functionClassName == null) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Verify the className in sinkConfig matches the fully-qualified name of a class implementing org.apache.pulsar.io.core.Sink in the archive
  2. Run `jar tf <archive>` (or inspect the NAR) to confirm the class file exists at the expected path
  3. Rebuild/re-upload the connector NAR or function package so it contains the sink class
  4. Confirm the connector is installed in the functions worker's connectors directory if using a built-in connector

Example fix

// before
sinkConfig.setClassName("org.example.MySinkt");
// after
sinkConfig.setClassName("org.example.MySink");
Defensive patterns

Strategy: validation

Validate before calling

try (Closer c = Closer.create()) {
  // verify class exists in the archive before submitting
  try (java.util.jar.JarFile jar = new java.util.jar.JarFile(archivePath)) {
    String entry = sinkClassName.replace('.', '/') + ".class";
    if (jar.getJarEntry(entry) == null) {
      throw new IllegalStateException("Sink class " + sinkClassName + " not in archive");
    }
  }
}

Try / catch

try {
  admin.sinks().createSink(config, archivePath);
} catch (IllegalArgumentException e) {
  if (e.getMessage() != null && e.getMessage().contains("not found") && e.getMessage().startsWith("Sink class")) {
    log.error("Fix sinkConfig.className; class not present in uploaded archive", e);
  } else { throw e; }
}

Prevention

When it happens

Trigger: Creating/updating a sink whose className does not match any class inside the provided archive or built-in connector NAR; typo in the fully-qualified class name; the class is in the NAR but not visible to the functions worker's classloader.

Common situations: Typos in sinkConfig className; deploying a connector NAR built with a shaded/renamed class; uploading a custom jar missing the sink class; class name changed after a connector upgrade.

Related errors


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