{"record":{"id":"5770ef92440bbb86","repo":"apache/pulsar","slug":"period-can-not-be-null","errorCode":null,"errorMessage":"period can not be null","messagePattern":"period can not be null","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-common/src/main/java/org/apache/pulsar/common/util/SingleThreadNonConcurrentFixedRateScheduler.java","lineNumber":118,"sourceCode":"    @Override\n    public Future<?> submit(Runnable task) {\n        return super.submit(new SafeRunnable(task));\n    }\n\n    /***\n     * Different with {@link #scheduleAtFixedRate(Runnable, long, long, TimeUnit)}, If the execution time of the next\n     * period task > period: New tasks will trigger be dropped, instead, execute the next period task after the current\n     * time.\n     */\n    public ScheduledFuture<?> scheduleAtFixedRateNonConcurrently(Runnable command,\n                                                                 long initialDelay,\n                                                                 long period,\n                                                                 TimeUnit unit) {\n        if (command == null || unit == null) {\n            throw new NullPointerException();\n        }\n        if (period <= 0L) {\n            throw new IllegalArgumentException(\"period can not be null\");\n        }\n        ScheduledFutureTask<Void> sft =\n                new ScheduledFutureTask<Void>(command,\n                        null,\n                        triggerTime(initialDelay, unit),\n                        unit.toNanos(period),\n                        fixRateTaskSequencerGenerator.getAndIncrement());\n        RunnableScheduledFuture<Void> t = decorateTask(command, sft);\n        sft.outerTask = t;\n        delayedExecute(t);\n        return t;\n    }\n\n    /**\n     * Main execution method for delayed or periodic tasks.  If pool\n     * is shut down, rejects the task. Otherwise adds task to queue\n     * and starts a thread, if necessary, to run it.  (We cannot\n     * prestart the thread to run the task because the task (probably)","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-common/src/main/java/org/apache/pulsar/common/util/SingleThreadNonConcurrentFixedRateScheduler.java#L100-L136","documentation":"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.","triggerScenarios":"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').","commonSituations":"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.","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."],"exampleFix":"// before\nscheduler.scheduleAtFixedRateNonConcurrently(task, 0, periodFromConfig, TimeUnit.SECONDS); // periodFromConfig = 0\n// after\nif (periodFromConfig <= 0) { periodFromConfig = DEFAULT_PERIOD_SECONDS; }\nscheduler.scheduleAtFixedRateNonConcurrently(task, 0, periodFromConfig, TimeUnit.SECONDS);","handlingStrategy":"validation","validationCode":"static void validateScheduleArgs(Runnable command, long period, TimeUnit unit) {\n    java.util.Objects.requireNonNull(command, \"command\");\n    java.util.Objects.requireNonNull(unit, \"unit\");\n    if (period <= 0L) {\n        throw new IllegalArgumentException(\"period must be > 0, got: \" + period);\n    }\n}","typeGuard":"static boolean isValidPeriod(long period) { return period > 0L; }","tryCatchPattern":"try {\n    scheduler.scheduleAtFixedRateNonConcurrently(task, initialDelay, period, TimeUnit.SECONDS);\n} catch (IllegalArgumentException e) {\n    LOG.error(\"Invalid schedule period {} for task {}\", period, task, e);\n} catch (NullPointerException e) {\n    LOG.error(\"Null command or unit passed to scheduler\", e);\n}","preventionTips":["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"],"tags":["pulsar","scheduler","illegal-argument","argument-validation"],"backgroundTag":"invalid-scheduler-period","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"}