{"record":{"id":"f3f8d0b27441a01e","repo":"apache/pulsar","slug":"cron-trigger-is-not-provided-with-cron-string","errorCode":null,"errorMessage":"Cron Trigger is not provided with Cron String","messagePattern":"Cron Trigger is not provided with Cron String","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-io/batch-discovery-triggerers/src/main/java/org/apache/pulsar/io/batchdiscovery/CronTriggerer.java","lineNumber":68,"sourceCode":" * Firing times are resolved in the JVM's default time zone.\n */\n@CustomLog\npublic class CronTriggerer implements BatchSourceTriggerer {\n  public static final String CRON_KEY = \"__CRON__\";\n\n  private static final CronParser CRON_PARSER =\n          new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.SPRING53));\n\n  private String cronExpression;\n  private ExecutionTime executionTime;\n  private ScheduledExecutorService scheduler;\n\n  @Override\n  public void init(Map<String, Object> config, SourceContext sourceContext) {\n    if (config == null || config.containsKey(CRON_KEY)) {\n      cronExpression = (String) Objects.requireNonNull(config).get(CRON_KEY);\n    } else {\n      throw new IllegalArgumentException(\"Cron Trigger is not provided with Cron String\");\n    }\n    // Fail on a malformed expression here rather than at the first scheduling attempt.\n    executionTime = parse(cronExpression);\n\n    String threadNamePrefix = String.format(\"%s/%s/%s-cron-triggerer-\",\n            sourceContext.getTenant(), sourceContext.getNamespace(), sourceContext.getSourceName());\n    scheduler = Executors.newSingleThreadScheduledExecutor(newThreadFactory(threadNamePrefix));\n\n    log.info().attr(\"cronExpression\", cronExpression).log(\"Initialized CronTrigger\");\n  }\n\n  @Override\n  public void start(Consumer<String> trigger) {\n    scheduleNext(trigger, ZonedDateTime.now());\n  }\n\n  @Override\n  public void stop() {","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-io/batch-discovery-triggerers/src/main/java/org/apache/pulsar/io/batchdiscovery/CronTriggerer.java#L50-L86","documentation":"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.","triggerScenarios":"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.)","commonSituations":"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.","solutions":["Add the cron key to the source configuration, e.g. {\"triggerer\": \"CRON\", \"cron\": \"0 0/5 * * *\"}.","Validate the cron expression format (quartz-style) before submitting the source config.","If using a non-CRON triggerer, switch triggerer type to INTERVAL so the cron key is not required."],"exampleFix":"// before (source config)\n// {\"batchSourceTriggererClass\": \"CronTriggerer\"}   // no cron string\n// after\n// {\"batchSourceTriggererClass\": \"CronTriggerer\", \"cron\": \"0 0 * * *\"}","handlingStrategy":"validation","validationCode":"Object cron = config == null ? null : config.get(\"cron\");\nif (!(cron instanceof String s) || s.isBlank()) {\n    throw new IllegalArgumentException(\"'cron' must be a non-empty string for CronTriggerer\");\n}\nCronDefinition.instanceDefinitionFor(CronType.QUARTZ).validate? // use cron-utils parser to pre-validate\nCron.parse(s);","typeGuard":"boolean hasValidCron(Map<String, Object> config) {\n    Object v = config == null ? null : config.get(\"cron\");\n    return v instanceof String s && !s.isBlank();\n}","tryCatchPattern":"try {\n    triggerer.init(config, sourceContext);\n} catch (IllegalArgumentException e) {\n    log.error(\"Triggerer config invalid: {}\", e.getMessage());\n    throw new ConnectorConfigException(e.getMessage(), e);\n}","preventionTips":["Always include a non-empty 'cron' key when triggerer type is CRON","Pre-validate cron expressions with a parser before submitting source configs","Keep a template config per triggerer type in your deployment repo"],"tags":["pulsar-io","configuration","cron","illegalargument"],"backgroundTag":"missing-config-property","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}