// Copyright 2014 Google Inc. All Rights Reserved.
package com.google.appengine.tools.mapreduce;

import com.google.appengine.tools.mapreduce.impl.shardedjob.Status;

/**
 * An exception that is thrown upon MapReduceJob failure.
 */
public class MapReduceJobException extends RuntimeException {

  private static final long serialVersionUID = 2875093254119004898L;
  private final String stage;

  MapReduceJobException(String stage, Status status) {
    super("Stage " + stage + " was not completed successfuly (status="
        + status.getStatusCode() + ", message=" + status.getException().getMessage() + ")",
        status.getException());
    this.stage = stage;
  }

  /**
   * Returns a string representing the MapReduce stage that failed.
   * The exception propagated from the stage can be fetched by {@link #getCause()}.
   */
  public String getFailedStage() {
    return stage;
  }
}
@@ -514,24 +514,16 @@
 status=%22
-%0A       
  + statu
@@ -539,16 +539,24 @@
 usCode()
+%0A       
  + %22, me
@@ -590,36 +590,15 @@
 on()
-.getMessage() + %22)%22,%0A       
+ + %22)%22,
  sta

Fix NPE when job ABORTED. To prevent the job from failing with an NPE instead of a nicer "MapReduceJobException".