apache/hadoop · error · IOException

Reset called without a previous mark

Error message

Reset called without a previous mark

What it means

The special case in ValueIterator.reset(): when clearMark() is called during reset-mode iteration, clearMarkFlag stays set until the iteration finishes; the next reset() consumes the flag, clears the backup store's mark, and throws IOException('Reset called without a previous mark'). One rewind is granted per mark — once the mark is cleared, no live mark remains to reset to.

Solutions

  1. Call mark() again before every reset() you intend to use
  2. Treat clearMark() as terminal for that group — only clear when no further rewind is needed
  3. Encapsulate the mark/reset dance in one helper that tracks state explicitly
Defensive patterns

Strategy: validation

Validate before calling

class Rewinder {
  private final ValueIterator<KEYIN, VALUEIN> it;
  private boolean liveMark = false;
  void rewind() throws IOException {
    if (!liveMark) { it.mark(); liveMark = true; }
    it.reset();
  }
  void doneRewinding() throws IOException { it.clearMark(); liveMark = false; }
}

Try / catch

try {
  it.reset();
} catch (IOException e) { // 'Reset called without a previous mark'
  it.mark();
  it.reset();
}

Prevention

When it happens

Trigger: Sequence mark(); reset(); partial iteration; clearMark(); then reset() again without re-marking. The second reset lands here.

Common situations: Two-pass reducer logic that rewinds per key group and clears marks to free backup-store space, then rewinds once more on a corner case; hand-rolled mark/reset state machines losing track of whether the mark survives.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/8863f75ba6c9daf4. Report an issue: GitHub.

Appendix: source

Thrown at hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/task/ReduceContextImpl.java:287

          WritableUtils.getVIntSize(currentKeyLength) +
          WritableUtils.getVIntSize(currentValueLength);
        DataOutputStream out = backupStore.getOutputStream(requestedSize);
        writeFirstKeyValueBytes(out);
        backupStore.updateCounters(requestedSize);
      } else {
        backupStore.mark();
      }
    }

    @Override
    public void reset() throws IOException {
      // We reached the end of an iteration and user calls a 
      // reset, but a clearMark was called before, just throw
      // an exception
      if (clearMarkFlag) {
        clearMarkFlag = false;
        backupStore.clearMark();
        throw new IOException("Reset called without a previous mark");
      }
      
      if (!isMarked) {
        throw new IOException("Reset called without a previous mark");
      }
      inReset = true;
      backupStore.reset();
    }

    @Override
    public void clearMark() throws IOException {
      if (getBackupStore() == null) {
        return;
      }
      if (inReset) {
        clearMarkFlag = true;
        backupStore.clearMark();
      } else {

View on GitHub (pinned to 2add963021)