apache/pulsar · error · IllegalArgumentException

Cron Trigger is not provided with Cron String

Error message

Cron Trigger is not provided with Cron String

What it means

CronTriggerer.init() requires the source configuration map to contain the CRON_KEY entry holding a valid cron expression. If the config lacks that key, it throws IllegalArgumentException('Cron Trigger is not provided with Cron String'). It is thrown eagerly at init so a malformed/missing cron string fails configuration time rather than at the first scheduled run.

Source

Thrown at pulsar-io/batch-discovery-triggerers/src/main/java/org/apache/pulsar/io/batchdiscovery/CronTriggerer.java:68

 * Firing times are resolved in the JVM's default time zone.
 */
@CustomLog
public class CronTriggerer implements BatchSourceTriggerer {
  public static final String CRON_KEY = "__CRON__";

  private static final CronParser CRON_PARSER =
          new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.SPRING53));

  private String cronExpression;
  private ExecutionTime executionTime;
  private ScheduledExecutorService scheduler;

  @Override
  public void init(Map<String, Object> config, SourceContext sourceContext) {
    if (config == null || config.containsKey(CRON_KEY)) {
      cronExpression = (String) Objects.requireNonNull(config).get(CRON_KEY);
    } else {
      throw new IllegalArgumentException("Cron Trigger is not provided with Cron String");
    }
    // Fail on a malformed expression here rather than at the first scheduling attempt.
    executionTime = parse(cronExpression);

    String threadNamePrefix = String.format("%s/%s/%s-cron-triggerer-",
            sourceContext.getTenant(), sourceContext.getNamespace(), sourceContext.getSourceName());
    scheduler = Executors.newSingleThreadScheduledExecutor(newThreadFactory(threadNamePrefix));

    log.info().attr("cronExpression", cronExpression).log("Initialized CronTrigger");
  }

  @Override
  public void start(Consumer<String> trigger) {
    scheduleNext(trigger, ZonedDateTime.now());
  }

  @Override
  public void stop() {

View on GitHub (pinned to 820761864e)

Solutions

  1. Add the cron key to the source configuration, e.g. {"triggerer": "CRON", "cron": "0 0/5 * * *"}.
  2. Validate the cron expression format (quartz-style) before submitting the source config.
  3. If using a non-CRON triggerer, switch triggerer type to INTERVAL so the cron key is not required.

Example fix

// before (source config)
// {"batchSourceTriggererClass": "CronTriggerer"}   // no cron string
// after
// {"batchSourceTriggererClass": "CronTriggerer", "cron": "0 0 * * *"}
Defensive patterns

Strategy: validation

Validate before calling

Object cron = config == null ? null : config.get("cron");
if (!(cron instanceof String s) || s.isBlank()) {
    throw new IllegalArgumentException("'cron' must be a non-empty string for CronTriggerer");
}
CronDefinition.instanceDefinitionFor(CronType.QUARTZ).validate? // use cron-utils parser to pre-validate
Cron.parse(s);

Type guard

boolean hasValidCron(Map<String, Object> config) {
    Object v = config == null ? null : config.get("cron");
    return v instanceof String s && !s.isBlank();
}

Try / catch

try {
    triggerer.init(config, sourceContext);
} catch (IllegalArgumentException e) {
    log.error("Triggerer config invalid: {}", e.getMessage());
    throw new ConnectorConfigException(e.getMessage(), e);
}

Prevention

When it happens

Trigger: Using batchdiscovery triggerer type 'CRON' in a Pulsar IO source config without the 'cron' key, or with a config map missing the entry. (Note: the current guard is `config.containsKey(CRON_KEY)`, so a null value under the key can also produce a downstream NullPointerException rather than this message.)

Common situations: Source config YAML/JSON for a batch-source forgetting the `"cron": "0 0 * * *"` property; copying a config from an interval-triggerer example; typo in the key name.

Related errors


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