{"record":{"id":"c58c5e84acaeac9a","repo":"apache/iceberg","slug":"no-mark-defined-or-has-read-past-the-previous-mark","errorCode":null,"errorMessage":"No mark defined or has read past the previous mark limit","messagePattern":"No mark defined or has read past the previous mark limit","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"warning","filePath":"core/src/main/java/org/apache/iceberg/io/MultiBufferInputStream.java","lineNumber":312,"sourceCode":"    }\n    this.mark = position;\n    this.markLimit = mark + readlimit + 1;\n    if (current != null) {\n      markBuffers.add(current.duplicate());\n    }\n  }\n\n  @Override\n  public void reset() throws IOException {\n    if (mark >= 0 && position < markLimit) {\n      this.position = mark;\n      // replace the current iterator with one that adds back the buffers that\n      // have been used since mark was called.\n      this.iterator = Iterators.concat(markBuffers.iterator(), iterator);\n      discardMark();\n      nextBuffer(); // go back to the marked buffers\n    } else {\n      throw new IOException(\"No mark defined or has read past the previous mark limit\");\n    }\n  }\n\n  private void discardMark() {\n    this.mark = -1;\n    this.markLimit = 0;\n    markBuffers = Lists.newArrayList();\n  }\n\n  @Override\n  public boolean markSupported() {\n    return true;\n  }\n\n  private boolean nextBuffer() {\n    if (!iterator.hasNext()) {\n      this.current = null;\n      return false;","sourceCodeStart":294,"sourceCodeEnd":330,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/io/MultiBufferInputStream.java#L294-L330","documentation":"MultiBufferInputStream supports mark/readmark only up to markLimit bytes read past the mark, because backward seeks beyond that would require buffers that were already discarded. reset() throws IOException('No mark defined or has read past the previous mark limit') when no mark is active or the read limit was exceeded. It is the standard InputStream mark/reset contract violation.","triggerScenarios":"Calling reset() before any mark() call; calling reset() after reading more than the readLimit passed to mark(readLimit); calling reset() twice (the first reset discards the mark via discardMark()).","commonSituations":"Avro/Parquet container readers calling reset() after lookahead exceeded the limit; mark() called with a too-small readLimit; reusing a stream across records where a second reset() has no valid mark.","solutions":["Call mark(readLimit) with a readLimit large enough to cover all lookahead before reading","Ensure reset() is called at most once per mark(); re-mark after each reset","Guard reset() with mark >= 0 checks or skip reset when no mark is defined","If unlimited reset is needed, buffer the data yourself or re-open the stream and seek instead","Catch IOException around reset() and fall back to re-seeking from a saved position"],"exampleFix":"// before\nstream.mark(16); // too small for actual lookahead\n... read 100 bytes ...\nstream.reset(); // IOException: read past mark limit\n// after\nstream.mark(1024); // limit >= maximum expected lookahead\n... read up to 1024 bytes ...\nstream.reset();","handlingStrategy":"try-catch","validationCode":"// before reset, ensure a mark is active\nif (stream.markLimit > 0 || stream.mark >= 0) { // track marks in wrapper if fields are private\n  stream.reset();\n} else {\n  stream.seek(savedPosition); // fallback\n}","typeGuard":null,"tryCatchPattern":"try {\n  stream.reset();\n} catch (IOException e) {\n  stream.seek(savedPosition); // fallback to explicit seek\n}","preventionTips":["Always pair mark(readLimit) with exactly one reset()","Size readLimit to the maximum possible lookahead, plus margin","Prefer explicit seek(bookmark) over mark/reset when positions are known"],"tags":["io","mark-reset","stream","invalid-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}