{"record":{"id":"8863f75ba6c9daf4","repo":"apache/hadoop","slug":"reset-called-without-a-previous-mark","errorCode":null,"errorMessage":"Reset called without a previous mark","messagePattern":"Reset called without a previous mark","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/task/ReduceContextImpl.java","lineNumber":287,"sourceCode":"          WritableUtils.getVIntSize(currentKeyLength) +\n          WritableUtils.getVIntSize(currentValueLength);\n        DataOutputStream out = backupStore.getOutputStream(requestedSize);\n        writeFirstKeyValueBytes(out);\n        backupStore.updateCounters(requestedSize);\n      } else {\n        backupStore.mark();\n      }\n    }\n\n    @Override\n    public void reset() throws IOException {\n      // We reached the end of an iteration and user calls a \n      // reset, but a clearMark was called before, just throw\n      // an exception\n      if (clearMarkFlag) {\n        clearMarkFlag = false;\n        backupStore.clearMark();\n        throw new IOException(\"Reset called without a previous mark\");\n      }\n      \n      if (!isMarked) {\n        throw new IOException(\"Reset called without a previous mark\");\n      }\n      inReset = true;\n      backupStore.reset();\n    }\n\n    @Override\n    public void clearMark() throws IOException {\n      if (getBackupStore() == null) {\n        return;\n      }\n      if (inReset) {\n        clearMarkFlag = true;\n        backupStore.clearMark();\n      } else {","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/task/ReduceContextImpl.java#L269-L305","documentation":"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.","triggerScenarios":"Sequence mark(); reset(); partial iteration; clearMark(); then reset() again without re-marking. The second reset lands here.","commonSituations":"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.","solutions":["Call mark() again before every reset() you intend to use","Treat clearMark() as terminal for that group — only clear when no further rewind is needed","Encapsulate the mark/reset dance in one helper that tracks state explicitly"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"class Rewinder {\n  private final ValueIterator<KEYIN, VALUEIN> it;\n  private boolean liveMark = false;\n  void rewind() throws IOException {\n    if (!liveMark) { it.mark(); liveMark = true; }\n    it.reset();\n  }\n  void doneRewinding() throws IOException { it.clearMark(); liveMark = false; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  it.reset();\n} catch (IOException e) { // 'Reset called without a previous mark'\n  it.mark();\n  it.reset();\n}","preventionTips":["Model mark/reset as an explicit state machine: mark, rewind, clear are distinct states","Re-mark before every rewind after a clearMark","Never assume a mark survives clearMark()"],"tags":["mapreduce","reducer","iterator","mark-reset","state-machine"],"backgroundTag":"reset-without-mark","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}