OpenFeign/feign · error · IOException

Mark not set

Error message

Mark not set

What it means

CountingInputStream.reset() throws IOException("Mark not set") when reset() is called before any mark() has established a position (internal mark field is -1). Per InputStream contract, reset is only valid after a prior mark.

Solutions

  1. Call mark(readlimit) before any read if you plan to reset
  2. Restructure code to read the stream once and buffer the bytes if re-reading is needed
  3. Check markSupported() and your mark position logic before resetting

Example fix

// before
is.read(); is.reset(); // Mark not set
// after
is.mark(8192);
is.read();
is.reset();
Defensive patterns

Strategy: validation

Validate before calling

if (stream.markSupported() && markPositionSet) { stream.reset(); }

Try / catch

try { stream.reset(); }
catch (IOException e) {
  if ("Mark not set".equals(e.getMessage())) { stream.mark(8192); /* restart read */ }
  else throw e;
}

Prevention

When it happens

Trigger: Calling reset() on the metered stream without ever calling mark(), or after the mark was invalidated; consuming more than readlimit then resetting.

Common situations: Custom retry/replay logic reading the response body twice; utility code assuming reset() always works; misuse of the CountingInputStream outside the Feign pipeline.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of OpenFeign/feign@e2a1e27560 (2026-09-10). Data as JSON: /api/errors/46c1afa17dee3a06. Report an issue: GitHub.

Appendix: source

Thrown at micrometer/src/main/java/feign/micrometer/CountingInputStream.java:88

    final long result = in.skip(n);
    count += result;
    return result;
  }

  @Override
  public synchronized void mark(int readlimit) {
    in.mark(readlimit);
    mark = count;
    // it's okay to mark even if mark isn't supported, as reset won't work
  }

  @Override
  public synchronized void reset() throws IOException {
    if (!in.markSupported()) {
      throw new IOException("Mark not supported");
    }
    if (mark == -1) {
      throw new IOException("Mark not set");
    }

    in.reset();
    count = mark;
  }
}

View on GitHub (pinned to e2a1e27560)