{"record":{"id":"d0b5b175d51954ce","repo":"apache/hadoop","slug":"invalid-job-run-state-runstate","errorCode":null,"errorMessage":"Invalid job run state : {runState}","messagePattern":"Invalid job run state : (.+?)","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/mapred/OutputCommitter.java","lineNumber":305,"sourceCode":"   */\n  @Override\n  public final void commitJob(org.apache.hadoop.mapreduce.JobContext context\n                             ) throws IOException {\n    commitJob((JobContext) context);\n  }\n  \n  /**\n   * This method implements the new interface by calling the old method. Note\n   * that the input types are different between the new and old apis and this\n   * is a bridge between the two.\n   */\n  @Override\n  public final void abortJob(org.apache.hadoop.mapreduce.JobContext context, \n\t\t                   org.apache.hadoop.mapreduce.JobStatus.State runState) \n  throws IOException {\n    int state = JobStatus.getOldNewJobRunState(runState);\n    if (state != JobStatus.FAILED && state != JobStatus.KILLED) {\n      throw new IOException (\"Invalid job run state : \" + runState.name());\n    }\n    abortJob((JobContext) context, state);\n  }\n  \n  /**\n   * This method implements the new interface by calling the old method. Note\n   * that the input types are different between the new and old apis and this\n   * is a bridge between the two.\n   */\n  @Override\n  public final \n  void setupTask(org.apache.hadoop.mapreduce.TaskAttemptContext taskContext\n                 ) throws IOException {\n    setupTask((TaskAttemptContext) taskContext);\n  }\n  \n  /**\n   * This method implements the new interface by calling the old method. Note","sourceCodeStart":287,"sourceCodeEnd":323,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapred/OutputCommitter.java#L287-L323","documentation":"This bridge adapts the new org.apache.hadoop.mapreduce OutputCommitter.abortJob(JobContext, State) to the old mapred API. It maps the enum via JobStatus.getOldNewJobRunState and accepts only FAILED and KILLED - the two states for which aborting a job is meaningful. Aborting with RUNNING or SUCCEEDED is a lifecycle programming error and throws this IOException.","triggerScenarios":"Calling committer.abortJob(ctx, JobStatus.State.SUCCEEDED) or State.RUNNING: unconditional cleanup blocks that abort regardless of outcome, AM state-machine bugs routing success through abort, or custom committers delegating to the bridge from a finally-style path.","commonSituations":"Custom committers wrapped around the old API; 'abort to be safe' cleanup code; MR1 code ported where abortJob(int) had been invoked with arbitrary states.","solutions":["Only invoke abortJob for FAILED/KILLED; call commitJob() on success and do nothing while RUNNING","Guard the call site on the final job state before delegating","When extending OutputCommitter, override the old-API abortJob(JobContext, int) - this final bridge enforces the state check for you"],"exampleFix":"// before\ncommitter.abortJob(jobContext, finalState); // runs even when finalState == SUCCEEDED\n\n// after\nif (finalState == JobStatus.State.FAILED || finalState == JobStatus.State.KILLED) {\n  committer.abortJob(jobContext, finalState);\n} else if (finalState == JobStatus.State.SUCCEEDED) {\n  committer.commitJob(jobContext);\n}","handlingStrategy":"validation","validationCode":"static boolean isAbortableState(org.apache.hadoop.mapreduce.JobStatus.State s) {\n  return s == org.apache.hadoop.mapreduce.JobStatus.State.FAILED\n      || s == org.apache.hadoop.mapreduce.JobStatus.State.KILLED;\n}\n// use: if (isAbortableState(finalState)) committer.abortJob(ctx, finalState);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Model the committer lifecycle explicitly: setupJob -> (commitJob | abortJob); never abort on success","Write a state-machine test asserting abortJob is unreachable for RUNNING/SUCCEEDED","Keep custom committers on one API layer and let the framework bridge do conversion"],"tags":["hadoop","mapreduce","outputcommitter","job-lifecycle","invalid-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}