{"record":{"id":"ef979ff40ad34dbd","repo":"ReactiveX/RxJava","slug":"count-0-expected-but-it-was","errorCode":null,"errorMessage":"count >= 0 expected but it was {}","messagePattern":"count >= 0 expected but it was (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/io/reactivex/rxjava4/core/Streamable.java","lineNumber":1020,"sourceCode":"     */\n    @CheckReturnValue\n    @NonNull\n    default Streamable<T> retryWhen(BiFunction<? super Long, ? super Throwable, ? extends CompletionStage<Boolean>> whenFunction) {\n        Objects.requireNonNull(whenFunction, \"whenFunction is null\");\n        return RxJavaPlugins.onAssembly(new StreamableRetry<>(this, whenFunction));\n    }\n\n    /**\n     * Skips the first {@code count} items and relays the rest to the downstream.\n     * @param count the number of items to skip\n     * @return the new {@code Streamable} instance\n     * @throws IllegalArgumentException if {@code count} is negative\n     */\n    @CheckReturnValue\n    @NonNull\n    default Streamable<T> skip(long count) {\n        if (count < 0) {\n            throw new IllegalArgumentException(\"count >= 0 expected but it was \" + count);\n        }\n        return RxJavaPlugins.onAssembly(new StreamableSkip<>(this, count));\n    }\n\n    /**\n     * Takes at most the given number of items from the upstream and relays it to the downstream,\n     * then cancels the rest of the sequence.\n     * <p>\n     * Note that cancellation of the upstream happens when the downstream\n     * calls {@link Streamer#next()} because unlike the push-based {@code take}\n     * implementations, the current upstream value has to remain accessible until\n     * the downstream calls {@code next} or {@link Streamer#finish()}.\n     * @param count the maximum number of items to relay\n     * @return the new {@code Streamable} instance\n     * @throws IllegalArgumentException if {@code count} is negative\n     */\n    @CheckReturnValue\n    @NonNull","sourceCodeStart":1002,"sourceCodeEnd":1038,"githubUrl":"https://github.com/ReactiveX/RxJava/blob/a8ab5356143f37a8f1dd6d76c79191bec5fa343b/src/main/java/io/reactivex/rxjava4/core/Streamable.java#L1002-L1038","documentation":"Thrown by Streamable.skip(long count) when count is negative. skip() drops the first `count` items and relays the rest; a negative skip is undefined and rejected at assembly time. Note this message uses the word 'expected' whereas repeat/take use 'required' — a minor wording inconsistency in the library, but the contract is identical.","triggerScenarios":"Calling streamable.skip(n) with n < 0. Typical when skip count is computed from an offset, page-size, or index expression that can underflow (e.g. skip = pageSize * (page - 1) when page is 0 or negative).","commonSituations":"Pagination math where a zero or negative page number is passed; user-supplied offset not sanitized; converting 1-based indices to 0-based skip values incorrectly.","solutions":["Clamp the skip value to >= 0 before calling skip(), treating negatives as 0 (skip nothing).","Validate page/offset inputs at the API/controller boundary so negative values never reach the stream pipeline.","Use Math.max(0, n) at the call site if a small number of calls are involved; otherwise centralize in a helper.","Test the boundary: skip(0) relays everything, skip(large) relays nothing, skip(-1) throws."],"exampleFix":"// before\nlong toSkip = pageSize * (page - 1); // page=0 -> negative\nsource.skip(toSkip).blockingSubscribe(...);\n\n// after\nlong toSkip = Math.max(0, pageSize * (page - 1));\nsource.skip(toSkip).blockingSubscribe(...);","handlingStrategy":"validation","validationCode":"long safeSkip(long count) {\n    return Math.max(0, count);\n}\n// then: source.skip(safeSkip(n))","typeGuard":null,"tryCatchPattern":"try {\n    source.skip(n).blockingSubscribe(...);\n} catch (IllegalArgumentException e) {\n    logger.warn(\"Invalid skip count {}\", n, e);\n}","preventionTips":["Validate page/offset inputs at the API boundary so negatives never reach skip().","When converting 1-based page numbers to skip amounts, guard page >= 1 first.","Clamp skip with Math.max(0, expr) at every call site that uses computed offsets."],"tags":["validation","argument","streamable","skip","rxjava"],"backgroundTag":null,"analyzedSha":"a8ab5356143f37a8f1dd6d76c79191bec5fa343b","analyzedAt":"2026-08-13T23:25:30.069Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}