ReactiveX/RxJava · error · IllegalArgumentException

count >= 0 required but it was {}

Error message

count >= 0 required but it was {}

What it means

Thrown by Observable.intervalRange when count is negative. The operator emits count longs; a negative count is invalid and rejected at assembly time before any scheduling. The offending value is interpolated into the message.

Source

Thrown at src/main/java/io/reactivex/rxjava4/core/Observable.java:2090

     * </dl>
     * @param start that start value of the range
     * @param count the number of values to emit in total, if zero, the operator emits an {@code onComplete} after the initial delay.
     * @param initialDelay the initial delay before signaling the first value (the start)
     * @param period the period between subsequent values
     * @param unit the unit of measure of the {@code initialDelay} and {@code period} amounts
     * @param scheduler the target scheduler where the values and terminal signals will be emitted
     * @return the new {@code Observable} instance
     * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null}
     * @throws IllegalArgumentException
     *             if {@code count} is negative, or if {@code start} + {@code count} &minus; 1 exceeds
     *             {@link Long#MAX_VALUE}
     */
    @CheckReturnValue
    @NonNull
    @SchedulerSupport(SchedulerSupport.CUSTOM)
    public static Observable<Long> intervalRange(long start, long count, long initialDelay, long period, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) {
        if (count < 0) {
            throw new IllegalArgumentException("count >= 0 required but it was " + count);
        }

        if (count == 0L) {
            return Observable.<Long>empty().delay(initialDelay, unit, scheduler);
        }

        long end = start + (count - 1);
        if (start > 0 && end < 0) {
            throw new IllegalArgumentException("Overflow! start + count is bigger than Long.MAX_VALUE");
        }
        Objects.requireNonNull(unit, "unit is null");
        Objects.requireNonNull(scheduler, "scheduler is null");

        return RxJavaPlugins.onAssembly(new ObservableIntervalRange(start, end, Math.max(0L, initialDelay), Math.max(0L, period), unit, scheduler));
    }

    /**
     * Returns an {@code Observable} that signals the given (constant reference) item and then completes.

View on GitHub (pinned to a8ab535614)

Solutions

  1. Validate count before the call: if (count < 0) handle the error or clamp to 0.
  2. Fix the upstream arithmetic producing the negative value.
  3. Default unknown counts to 0 so you get Observable.empty() behavior.

Example fix

// before
long count = remaining - 1; // can be negative
Observable.intervalRange(0, count, 0, 1, TimeUnit.SECONDS, scheduler);

// after
long count = remaining - 1;
Observable<Long> o = count < 0L
    ? Observable.empty()
    : Observable.intervalRange(0, count, 0, 1, TimeUnit.SECONDS, scheduler);
Defensive patterns

Strategy: validation

Validate before calling

if (count < 0L) {
    return Observable.empty();
}

Try / catch

try {
    return Observable.intervalRange(start, count, initialDelay, period, unit, scheduler);
} catch (IllegalArgumentException e) {
    return Observable.empty();
}

Prevention

When it happens

Trigger: Calling Observable.intervalRange(start, count, ...) with count < 0. Typical when count is derived from a computation or config that can go negative.

Common situations: Config-driven emission counts defaulting to -1; size calculations like available - consumed that underflow; untrusted inputs not bounds-checked.

Related errors


AI-assisted analysis of ReactiveX/RxJava@a8ab535614 (2026-08-13). Data as JSON: /api/errors/371544392b6f3c7b. Report an issue: GitHub.