didi/DoKit · error · IOException
Cannot reset
Error message
Cannot reset
What it means
MarkableInputStream.reset(token) throws IOException("Cannot reset") when the current offset has passed the marked limit or the requested token is before the earliest valid reset point. The mark window is bounded by the readlimit given to the underlying stream, so once data has been read past it, rewinding is impossible.
Source
Thrown at Android/dokit/src/main/java/com/didichuxing/doraemonkit/picasso/MarkableInputStream.java:99
} else {
reset = offset;
in.mark((int) (limit - offset));
}
this.limit = limit;
} catch (IOException e) {
throw new IllegalStateException("Unable to mark: " + e);
}
}
/** Resets the stream to the most recent {@link #mark mark}. */
@Override public void reset() throws IOException {
reset(defaultMark);
}
/** Resets the stream to the position recorded by {@code token}. */
public void reset(long token) throws IOException {
if (offset > limit || token < reset) {
throw new IOException("Cannot reset");
}
in.reset();
skip(reset, token);
offset = token;
}
/** Skips {@code target - current} bytes and returns. */
private void skip(long current, long target) throws IOException {
while (current < target) {
long skipped = in.skip(target - current);
if (skipped == 0) {
if (read() == -1) {
break; // EOF
} else {
skipped = 1;
}
}
current += skipped;View on GitHub (pinned to 626827cddb)
Solutions
- Reset promptly after reading, before consuming bytes beyond the mark window
- Increase the mark limit / buffer the stream fully when large rewinds are needed
- Catch the IOException at the decode layer and retry by re-requesting the stream from the Downloader
Example fix
// before long token = stream.savePosition(0); inspectManyBytes(stream); stream.reset(token); // IOException: Cannot reset // after long token = stream.savePosition(0); inspectFewBytes(stream); stream.reset(token); // or re-open the stream and start a fresh decode on IOException
Defensive patterns
Strategy: try-catch
Validate before calling
// structural prevention only: read little before reset, or buffer fully
if (!streamIsBig && bytesToInspect > MARK_WINDOW) { stream = new BufferedInputStream(stream, bytesToInspect); } Try / catch
try { stream.reset(token); } catch (IOException e) { if ("Cannot reset".equals(e.getMessage())) { stream = reopenStream(); /* fresh decode */ } else { throw e; } } Prevention
- Reset soon after marking; do not read past the mark window before rewinding
- Buffer the stream when large inspections precede the real decode
- On IOException from reset, prefer re-opening the stream over forcing the rewind
When it happens
Trigger: Calling reset(token) after reading more bytes than the saved mark window covers, or resetting to a token older than the current reset floor (e.g. resetting twice to progressively earlier positions).
Common situations: Decoding logic that inspects many bytes (multiple bounds decodes, EXIF scanning) before rewinding; reused streams where reset is attempted after a previous reset shrank the window.
Related errors
- Unable to mark: <e>
- Mark not supported
- Failed to decode stream.
- closed
- Unrecognized type of request: " + request
AI-assisted analysis of didi/DoKit@626827cddb (2026-08-14).
Data as JSON: /api/errors/78c3e203ca2a4ad2.
Report an issue: GitHub.