apache/pulsar · error · IllegalArgumentException

Not support to set removeOnCancelPolicy, it is always false

Error message

Not support to set removeOnCancelPolicy, it is always false

What it means

SingleThreadNonConcurrentFixedRateScheduler does not support the removeOnCancelPolicy. Because DelayedWorkQueue.remove(runnable) is expensive when queued tasks are not of the same type, cancellation never removes tasks from the queue (policy is always false), and setRemoveOnCancelPolicy unconditionally throws IllegalArgumentException.

Source

Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/util/SingleThreadNonConcurrentFixedRateScheduler.java:235

                + " always false");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy() {
        return false;
    }

    /**
     * {@inheritDoc}
     * Since the method "remove(runnable)" of DelayedWorkQueue is expensive if the tasks in the queue is not the same
     * type, we denied the remove policy.
     */
    @Override
    public void setRemoveOnCancelPolicy(boolean value) {
        throw new IllegalArgumentException("Not support to set removeOnCancelPolicy, it is always false");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean getRemoveOnCancelPolicy() {
        return false;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
        super.setRejectedExecutionHandler(handler);
        this.rejectedExecutionHandler = handler;
    }

View on GitHub (pinned to 820761864e)

Solutions

  1. Remove the call to setRemoveOnCancelPolicy; cancelled tasks remain until they fire but the scheduler denies removal by design.
  2. If cancelled-task accumulation is a concern, minimize scheduling of tasks that will be cancelled immediately, or use ScheduledThreadPoolExecutor with setRemoveOnCancelPolicy(true).
  3. Wrap policy-setting calls in a check for ScheduledThreadPoolExecutor before invoking the setter.
  4. Catch IllegalArgumentException in generic configuration code that must handle mixed executor types.

Example fix

// before
scheduler.setRemoveOnCancelPolicy(true);
// after
if (scheduler instanceof java.util.concurrent.ScheduledThreadPoolExecutor) {
    ((java.util.concurrent.ScheduledThreadPoolExecutor) scheduler).setRemoveOnCancelPolicy(true);
}
Defensive patterns

Strategy: try-catch

Validate before calling

static boolean supportsRemoveOnCancel(java.util.concurrent.ScheduledExecutorService s) {
    return s instanceof java.util.concurrent.ScheduledThreadPoolExecutor;
}

Type guard

static boolean isPolicyConfigurable(java.util.concurrent.ScheduledExecutorService s) {
    return s instanceof java.util.concurrent.ScheduledThreadPoolExecutor;
}

Try / catch

try {
    scheduler.setRemoveOnCancelPolicy(true);
} catch (IllegalArgumentException e) {
    LOG.info("Scheduler {} does not support removeOnCancelPolicy (always false): {}", scheduler, e.getMessage());
}

Prevention

When it happens

Trigger: Calling setRemoveOnCancelPolicy(true or false) on a SingleThreadNonConcurrentFixedRateScheduler, typically from generic executor-tuning code that calls the setter on any ScheduledExecutorService to avoid cancelled tasks piling up in the queue.

Common situations: Performance-tuning snippets written for ScheduledThreadPoolExecutor (where setRemoveOnCancelPolicy(true) is a common recommendation) applied to this Pulsar scheduler; long-lived schedulers with many cancellations where a developer tries to enable queue pruning; migration from java.util.concurrent schedulers.

Related errors


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