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

  1. Reset promptly after reading, before consuming bytes beyond the mark window
  2. Increase the mark limit / buffer the stream fully when large rewinds are needed
  3. 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

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


AI-assisted analysis of didi/DoKit@626827cddb (2026-08-14). Data as JSON: /api/errors/78c3e203ca2a4ad2. Report an issue: GitHub.