{"record":{"id":"29bbe2ee1b6f3788","repo":"quarkusio/quarkus","slug":"last-index-must-be-0","errorCode":null,"errorMessage":"Last index must be >= 0: ","messagePattern":"Last index must be >= 0: ","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/panache/panache-common/runtime/src/main/java/io/quarkus/panache/common/Range.java","lineNumber":33,"sourceCode":" *\n * Note that due to the end index being inclusive, it's impossible to write empty ranges.\n */\npublic class Range {\n    // FIXME: bump to long? Jakarta Data uses longs for its Limit type\n    private final int startIndex;\n    private final int lastIndex;\n\n    /**\n     * Creates a new range\n     *\n     * @param startIndex the start index to include, 0-based\n     * @param lastIndex the end index to include, 0-based\n     */\n    public Range(int startIndex, int lastIndex) {\n        if (startIndex < 0)\n            throw new IllegalArgumentException(\"Start index must be >= 0: \" + startIndex);\n        if (lastIndex < 0)\n            throw new IllegalArgumentException(\"Last index must be >= 0: \" + lastIndex);\n        if (lastIndex < startIndex)\n            throw new IllegalArgumentException(\n                    \"Last index must be >= start index: \" + lastIndex + \" is not larger or equal to \" + startIndex);\n        this.startIndex = startIndex;\n        this.lastIndex = lastIndex;\n    }\n\n    /**\n     * Creates a new range\n     *\n     * @param startIndex the start index to include, 0-based\n     * @param lastIndex the end index to include, 0-based\n     */\n    public static Range of(int startIndex, int lastIndex) {\n        return new Range(startIndex, lastIndex);\n    }\n\n    /**","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/panache/panache-common/runtime/src/main/java/io/quarkus/panache/common/Range.java#L15-L51","documentation":"Thrown by the Range constructor when lastIndex is negative. Range models an inclusive 0-based index window for Panache queries (and, per the class note, cannot represent empty ranges); a negative end index would describe a backwards or empty window, so the constructor guard rejects it immediately — mirroring the preceding check that startIndex must be >= 0.","triggerScenarios":"Calling new Range(0, -1) or Range.of with a negative end — e.g. end computed as start+count-1 with count=0, or an unvalidated negative lastIndex input.","commonSituations":"Empty result windows (count 0 leading to end=-1); client-provided negative end parameters; slice math on empty collections.","solutions":["Validate inputs: reject or clamp lastIndex to >= 0 before constructing.","Handle the empty-window case explicitly (skip the query or use Range.of(0, 0)) instead of computing end=-1.","Return HTTP 400 for client-supplied negative end indexes."],"exampleFix":"// before\nRange r = Range.of(0, count - 1); // count=0 -> -1\n// after\nif (count > 0) { Range r = Range.of(0, count - 1); ... }","handlingStrategy":"validation","validationCode":"int end = /* computed */;\nif (end < 0) throw new BadRequestException(\"lastIndex must be >= 0\");\nRange r = Range.of(start, end);","typeGuard":"Range safeRange(int start, int last) {\n    int s = Math.max(0, start);\n    return Range.of(s, Math.max(s, last));\n}","tryCatchPattern":"try {\n    Range r = Range.of(start, last);\n} catch (IllegalArgumentException e) {\n    throw new BadRequestException(\"Invalid range: \" + e.getMessage());\n}","preventionTips":["Handle empty windows (count=0) explicitly before computing end=count-1","Validate end indexes in request DTOs","Clamp lastIndex with Math.max(0, last)"],"tags":["panache","range","pagination","illegal-argument"],"backgroundTag":"invalid-pagination-index","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}