{"record":{"id":"c1c84146073f40af","repo":"apache/dubbo","slug":"read-ahead-limit-0","errorCode":null,"errorMessage":"Read-ahead limit < 0","messagePattern":"Read-ahead limit < 0","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"dubbo-common/src/main/java/org/apache/dubbo/common/io/UnsafeStringReader.java","lineNumber":94,"sourceCode":"        mPosition += n;\n        return n;\n    }\n\n    @Override\n    public boolean ready() throws IOException {\n        ensureOpen();\n        return true;\n    }\n\n    @Override\n    public boolean markSupported() {\n        return true;\n    }\n\n    @Override\n    public void mark(int readAheadLimit) throws IOException {\n        if (readAheadLimit < 0) {\n            throw new IllegalArgumentException(\"Read-ahead limit < 0\");\n        }\n\n        ensureOpen();\n        mMark = mPosition;\n    }\n\n    @Override\n    public void reset() throws IOException {\n        ensureOpen();\n        mPosition = mMark;\n    }\n\n    @Override\n    public void close() throws IOException {\n        mString = null;\n    }\n\n    private void ensureOpen() throws IOException {","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-common/src/main/java/org/apache/dubbo/common/io/UnsafeStringReader.java#L76-L112","documentation":"Thrown by UnsafeStringReader.mark(int) when the readAheadLimit argument is negative. UnsafeStringReader is a thread-unsafe Reader over a String that supports mark/reset; the limit parameter is accepted to honor the java.io.Reader contract but the implementation only records the current position (mMark = mPosition), so a negative value has no valid meaning and is rejected up front before ensureOpen() runs. This mirrors the behavior of java.io.StringReader.","triggerScenarios":"Calling reader.mark(readAheadLimit) on an UnsafeStringReader instance where readAheadLimit < 0 (e.g. mark(-1), mark(-1024)). The check at line 93 fires before the stream-open check, so even an open reader throws this first.","commonSituations":"Caller computes readAheadLimit from a length/offset that underflows to negative; passing a constant -1 as a 'no limit' sentinel (this API has no such sentinel); unit tests asserting mark behavior; code ported from a Reader that tolerates negative limits.","solutions":["Pass a non-negative readAheadLimit (the actual byte budget you intend to re-read after reset), e.g. mark(buffer.length()).","If the limit is computed, clamp it with Math.max(0, computed) before calling mark.","Guard the call: if (readAheadLimit >= 0) reader.mark(readAheadLimit); else skip marking.","Note UnsafeStringReader ignores the magnitude of the limit (it only stores mPosition), so any non-negative value works and 'unlimited' mark is effectively free."],"exampleFix":"// before\nreader.mark(-1);\n// after\nreader.mark(Integer.MAX_VALUE); // value is stored but not enforced by this impl","handlingStrategy":"validation","validationCode":"if (readAheadLimit < 0) {\n    // UnsafeStringReader stores position only; pass any non-negative value\n    readAheadLimit = 0;\n}\nreader.mark(readAheadLimit);","typeGuard":null,"tryCatchPattern":"try {\n    reader.mark(readAheadLimit);\n} catch (IllegalArgumentException e) {\n    if (\"Read-ahead limit < 0\".equals(e.getMessage())) {\n        reader.mark(0); // recover: zero is valid for this impl\n    } else {\n        throw e;\n    }\n}","preventionTips":["Clamp any computed read-ahead limit with Math.max(0, value) before calling mark.","Remember UnsafeStringReader ignores the magnitude of the limit (it only records mPosition), so 'unlimited' mark is effectively free — never pass a sentinel -1.","Do not use negative numbers as 'no limit' sentinels for Reader.mark APIs."],"tags":["io","string-reader","argument-validation","dubbo-common"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}