apache/pulsar · error · IllegalArgumentException

BatchSourceTriggerer does not implement the correct interfac

Error message

BatchSourceTriggerer does not implement the correct interface

What it means

In the same initializeBatchSource flow, the discovery triggerer class is instantiated via Reflections.createInstance and must implement BatchSourceTriggerer. Thrown when the configured discoveryTriggererClassName resolves to an object that does not implement that interface.

Source

Thrown at pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/source/batch/BatchSourceExecutor.java:149

    Object userClassObject = Reflections.createInstance(
      batchSourceClassName,
      clsLoader);
    if (userClassObject instanceof BatchSource) {
      @SuppressWarnings("unchecked") // type parameter is erased at runtime
      BatchSource<T> typedBatchSource = (BatchSource<T>) userClassObject;
      batchSource = typedBatchSource;
    } else {
      throw new IllegalArgumentException("BatchSource does not implement the correct interface");
    }

    // next init the discovery triggerer
    Object discoveryClassObject = Reflections.createInstance(
      batchSourceConfig.getDiscoveryTriggererClassName(),
      clsLoader);
    if (discoveryClassObject instanceof BatchSourceTriggerer) {
      discoveryTriggerer = (BatchSourceTriggerer) discoveryClassObject;
    } else {
      throw new IllegalArgumentException("BatchSourceTriggerer does not implement the correct interface");
    }
  }

  private void start() throws Exception {
    isRunning = true;
    createIntermediateTopicConsumer();
    batchSource.open(this.config, this.sourceContext);
    if (sourceContext.getInstanceId() == 0) {
      discoveryTriggerer.init(batchSourceConfig.getDiscoveryTriggererConfig(),
        this.sourceContext);
      discoveryTriggerer.start(this::triggerDiscover);
    }
  }

  volatile boolean discoverInProgress = false;
  private synchronized void triggerDiscover(String discoveredEvent) {

    if (discoverInProgress) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Set discoveryTriggererClassName to a class implementing org.apache.pulsar.io.core.BatchSourceTriggerer.
  2. Implement init/hasMore/activate methods per the current BatchSourceTriggerer interface.
  3. Rebuild the connector archive so the correct triggerer class is present in the NAR classloader.

Example fix

// before
public class MyTriggerer implements SourceTriggerer { ... }
// after
public class MyTriggerer implements BatchSourceTriggerer {
  public void init(BatchSourceConfig cfg, Map<String,Object> conf, Consumer<byte[]> consumer) {...}
  ...
}
Defensive patterns

Strategy: validation

Validate before calling

Class<?> c = Class.forName(discoveryTriggererClassName);
if (!BatchSourceTriggerer.class.isAssignableFrom(c)) {
  throw new IllegalArgumentException(discoveryTriggererClassName + " is not a BatchSourceTriggerer");
}

Type guard

boolean isBatchSourceTriggerer(Object o) { return o instanceof BatchSourceTriggerer; }

Try / catch

try {
  executor.open(config);
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("BatchSourceTriggerer does not implement")) {
    log.error("discoveryTriggererClassName must implement BatchSourceTriggerer");
  }
}

Prevention

When it happens

Trigger: batchSourceConfig.getDiscoveryTriggererClassName() names a class that instantiates successfully but is not a BatchSourceTriggerer, during open() -> initializeBatchSource.

Common situations: Wrong class name in the BatchSourceConfig (e.g. pointing at the BatchSource or an event-handler class); implementing the trigger logic against an older interface signature; copying a config between projects where the triggerer class changed.

Related errors


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