{"record":{"id":"0e8e1c03736fdf60","repo":"jhy/jsoup","slug":"resetting-to-invalid-mark","errorCode":null,"errorMessage":"Resetting to invalid mark","messagePattern":"Resetting to invalid mark","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/jsoup/internal/ControllableInputStream.java","lineNumber":190,"sourceCode":"                    newBuffer.put(outBuf);\n                    outBuf = newBuffer;\n                }\n                outBuf.put(readBuf, 0, read);\n                if (capped) {\n                    remaining -= read;\n                    if (remaining <= 0) break;\n                }\n            }\n            outBuf.flip(); // Prepare the buffer for reading\n            return outBuf;\n        } finally {\n            SimpleBufferedInput.BufferPool.release(readBuf);\n        }\n    }\n\n    @SuppressWarnings(\"NonSynchronizedMethodOverridesSynchronizedMethod\") // not synchronized in later JDKs\n    @Override public void reset() throws IOException {\n        if (markPos < 0) throw new IOException(\"Resetting to invalid mark\");\n        buff.rewindToMark();\n        buff.clearMark();\n        truncated = false;\n        if (maxSize != 0) {\n            remaining = maxSize - markPos;\n            buff.capRemaining(remaining);\n        } else {\n            remaining = 0;\n            buff.uncap();\n        }\n        readPos = markPos; // readPos is used for progress emits\n        markPos = -1;\n    }\n\n    @SuppressWarnings(\"NonSynchronizedMethodOverridesSynchronizedMethod\") // not synchronized in later JDKs\n    @Override public void mark(int readlimit) {\n        markPos = readPos;\n        buff.setMark();","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/jhy/jsoup/blob/9851ac5d9c576c6888910b5a51a2362bbc978959/src/main/java/org/jsoup/internal/ControllableInputStream.java#L172-L208","documentation":"ControllableInputStream.reset() throws IOException('Resetting to invalid mark') when there is no valid mark (markPos < 0), i.e. reset() was called without a prior mark(), or the mark was invalidated. jsoup uses mark/reset internally for BOM/charset detection and lookahead; callers can also hit it via the stream's mark/reset contract.","triggerScenarios":"Calling reset() on a ControllableInputStream (or wrapping stream) before any mark() call; calling reset() after reading beyond the readLimit given to mark(); mark cleared after jsoup finishes charset detection and the caller resets again.","commonSituations":"Wrapping jsoup's connection stream and hand-rolling mark/reset logic; reading more bytes than the mark limit during manual charset sniffing; reusing a stream after parse() consumed and invalidated marks.","solutions":["Always call mark(readlimit) before reset(), with readlimit larger than bytes you'll read.","Track whether mark is valid in your own wrapper; guard reset() accordingly.","Don't reset after jsoup's parse/charset detection has consumed the stream; re-request or buffer instead.","Wrap in BufferedInputStream with a generous buffer size if you need mark/reset yourself.","For retryable reads, read fully into a byte[] and use ByteArrayInputStream instead of resetting."],"exampleFix":"// before\nin.reset(); // no mark set\n// after\nin.mark(8192);\n// ... read header ...\nin.reset();","handlingStrategy":"validation","validationCode":"boolean canReset = ((ControllableInputStream) in).markSupported() && markIsActive; // track your own mark state\nif (!canReset) skip reset;","typeGuard":null,"tryCatchPattern":"try { in.reset(); } catch (IOException e) { if (e.getMessage().contains(\"invalid mark\")) { /* reopen or re-buffer instead */ } }","preventionTips":["Always pair mark(readlimit) with reset(); size readlimit generously.","Assume marks are invalidated after reading more than readlimit bytes.","Don't reset streams after jsoup parse/charset detection consumed them.","Prefer re-fetching or buffering bytes over stream rewinds."],"tags":["io","stream","mark-reset","invalid-mark"],"backgroundTag":"invalid-state-transition","analyzedSha":"9851ac5d9c576c6888910b5a51a2362bbc978959","analyzedAt":"2026-09-08T15:22:04.931Z","contentChangedAt":"2026-09-08T15:22:04.931Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}