apache/pulsar · error · IllegalArgumentException
period can not be null
Error message
period can not be null
What it means
SingleThreadNonConcurrentFixedRateScheduler.scheduleAtFixedRateNonConcurrently validates its inputs: a null command or null unit throws NullPointerException (mirroring ScheduledExecutorService semantics), and a period <= 0 throws this IllegalArgumentException. Despite the message text 'can not be null', the condition is actually a non-positive period — the message is misleading but the trigger is period <= 0.
Source
Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/util/SingleThreadNonConcurrentFixedRateScheduler.java:118
@Override
public Future<?> submit(Runnable task) {
return super.submit(new SafeRunnable(task));
}
/***
* Different with {@link #scheduleAtFixedRate(Runnable, long, long, TimeUnit)}, If the execution time of the next
* period task > period: New tasks will trigger be dropped, instead, execute the next period task after the current
* time.
*/
public ScheduledFuture<?> scheduleAtFixedRateNonConcurrently(Runnable command,
long initialDelay,
long period,
TimeUnit unit) {
if (command == null || unit == null) {
throw new NullPointerException();
}
if (period <= 0L) {
throw new IllegalArgumentException("period can not be null");
}
ScheduledFutureTask<Void> sft =
new ScheduledFutureTask<Void>(command,
null,
triggerTime(initialDelay, unit),
unit.toNanos(period),
fixRateTaskSequencerGenerator.getAndIncrement());
RunnableScheduledFuture<Void> t = decorateTask(command, sft);
sft.outerTask = t;
delayedExecute(t);
return t;
}
/**
* Main execution method for delayed or periodic tasks. If pool
* is shut down, rejects the task. Otherwise adds task to queue
* and starts a thread, if necessary, to run it. (We cannot
* prestart the thread to run the task because the task (probably)View on GitHub (pinned to 820761864e)
Solutions
- Pass a strictly positive period (period > 0) to scheduleAtFixedRateNonConcurrently.
- Validate/normalize the configured interval before scheduling and clamp or reject zero/negative values.
- Check where the period value originates (config parsing, unit conversion) to fix the source of the zero/negative value.
- If a run-once semantic was intended, use schedule() with an initialDelay instead of a fixed-rate schedule with period 0.
Example fix
// before
scheduler.scheduleAtFixedRateNonConcurrently(task, 0, periodFromConfig, TimeUnit.SECONDS); // periodFromConfig = 0
// after
if (periodFromConfig <= 0) { periodFromConfig = DEFAULT_PERIOD_SECONDS; }
scheduler.scheduleAtFixedRateNonConcurrently(task, 0, periodFromConfig, TimeUnit.SECONDS); Defensive patterns
Strategy: validation
Validate before calling
static void validateScheduleArgs(Runnable command, long period, TimeUnit unit) {
java.util.Objects.requireNonNull(command, "command");
java.util.Objects.requireNonNull(unit, "unit");
if (period <= 0L) {
throw new IllegalArgumentException("period must be > 0, got: " + period);
}
} Type guard
static boolean isValidPeriod(long period) { return period > 0L; } Try / catch
try {
scheduler.scheduleAtFixedRateNonConcurrently(task, initialDelay, period, TimeUnit.SECONDS);
} catch (IllegalArgumentException e) {
LOG.error("Invalid schedule period {} for task {}", period, task, e);
} catch (NullPointerException e) {
LOG.error("Null command or unit passed to scheduler", e);
} Prevention
- Validate configured intervals are strictly positive before scheduling
- Clamp zero/negative periods from config to a sane default at load time
- Use schedule() with a delay for one-shot semantics instead of period <= 0
- Check unit conversions (ms/s/min) for integer division truncation that can yield 0
When it happens
Trigger: Calling scheduleAtFixedRateNonConcurrently(command, initialDelay, period, unit) with period <= 0 (e.g. 0 or negative values computed from configuration, integer underflow, or a misparsed interval of '0').
Common situations: Configuration value for task interval is 0 or negative because a config key defaulted to 0, a properties file had 'period=0', or arithmetic (e.g. maxInterval - minInterval) produced 0; also seen when porting code that previously relied on ScheduledThreadPoolExecutor throwing NPE/IAE ordering differently.
Related errors
- ResourceGroupCreate: Invalid null ResourceGroup config
- ResourceGroupCreate: can't create resource group with an emp
- Invalid key-shared mode: ${keySharedMode}
- Invalid auto split/merge configuration: ${message}
- Must have at least 1 segment
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/5770ef92440bbb86.
Report an issue: GitHub.