You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@drill.apache.org by ja...@apache.org on 2015/04/15 17:56:03 UTC

[2/6] drill git commit: DRILL-2675: Implement a subset of User Exceptions to improve how errors are reported to the user

DRILL-2675: Implement a subset of User Exceptions to improve how errors are reported to the user


Project: http://git-wip-us.apache.org/repos/asf/drill/repo
Commit: http://git-wip-us.apache.org/repos/asf/drill/commit/99b6d0e6
Tree: http://git-wip-us.apache.org/repos/asf/drill/tree/99b6d0e6
Diff: http://git-wip-us.apache.org/repos/asf/drill/diff/99b6d0e6

Branch: refs/heads/master
Commit: 99b6d0e6d2fc6dea165e9e809db4fc63d9a70d3a
Parents: 859e6a8
Author: adeneche <ad...@gmail.com>
Authored: Thu Apr 9 09:30:33 2015 -0700
Committer: Jacques Nadeau <ja...@apache.org>
Committed: Wed Apr 15 07:02:10 2015 -0700

----------------------------------------------------------------------
 .../common/exceptions/DrillRemoteException.java |  44 ++
 .../common/exceptions/DrillUserException.java   | 204 ++++++++++
 .../drill/common/exceptions/ErrorHelper.java    | 186 +++++++++
 .../common/exceptions/UserExceptionContext.java | 148 +++++++
 .../exceptions/TestDrillUserException.java      | 130 ++++++
 .../apache/drill/exec/client/DrillClient.java   |   5 +-
 .../exec/client/PrintingResultsListener.java    |   9 +-
 .../apache/drill/exec/ops/FragmentContext.java  |  17 +-
 .../drill/exec/physical/impl/ScreenCreator.java |   2 -
 .../drill/exec/planner/sql/DrillSqlWorker.java  |  18 +-
 .../drill/exec/rpc/CoordinationQueue.java       |   3 +-
 .../drill/exec/rpc/RemoteRpcException.java      |  43 --
 .../java/org/apache/drill/exec/rpc/RpcBus.java  |  12 +-
 .../drill/exec/rpc/user/QueryResultHandler.java |  28 +-
 .../exec/rpc/user/UserResultsListener.java      |   4 +-
 .../drill/exec/server/rest/QueryWrapper.java    |   6 +-
 .../exec/store/easy/json/JSONRecordReader.java  |  28 +-
 .../org/apache/drill/exec/work/ErrorHelper.java | 229 -----------
 .../apache/drill/exec/work/foreman/Foreman.java |  17 +-
 .../drill/exec/work/foreman/QueryManager.java   |   4 +-
 .../work/foreman/SqlUnsupportedException.java   |   4 +-
 .../work/fragment/AbstractStatusReporter.java   |  14 +-
 .../exec/work/fragment/FragmentExecutor.java    |  13 +-
 .../exec/work/fragment/StatusReporter.java      |   3 +-
 .../java/org/apache/drill/BaseTestQuery.java    |  11 +-
 .../org/apache/drill/SingleRowListener.java     |   6 +-
 .../java/org/apache/drill/TestBugFixes.java     |   6 +-
 .../apache/drill/TestDisabledFunctionality.java | 140 +++----
 .../java/org/apache/drill/TestStarQueries.java  |   6 +-
 .../java/org/apache/drill/TestUnionAll.java     |   8 +-
 .../exec/server/TestDrillbitResilience.java     |  22 +-
 .../store/parquet/ParquetResultListener.java    |   8 +-
 .../store/parquet/TestParquetPhysicalPlan.java  |   4 +-
 .../java/org/apache/drill/jdbc/DrillCursor.java |   4 +-
 .../drill/jdbc/impl/DrillResultSetImpl.java     |   8 +-
 .../drill/exec/proto/SchemaUserBitShared.java   |   4 +-
 .../apache/drill/exec/proto/UserBitShared.java  | 408 +++++++++++++------
 .../drill/exec/proto/beans/DrillPBError.java    |  58 ++-
 protocol/src/main/protobuf/UserBitShared.proto  |  14 +-
 39 files changed, 1268 insertions(+), 610 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/common/src/main/java/org/apache/drill/common/exceptions/DrillRemoteException.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/drill/common/exceptions/DrillRemoteException.java b/common/src/main/java/org/apache/drill/common/exceptions/DrillRemoteException.java
new file mode 100644
index 0000000..7b707a5
--- /dev/null
+++ b/common/src/main/java/org/apache/drill/common/exceptions/DrillRemoteException.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.common.exceptions;
+
+import org.apache.drill.exec.proto.UserBitShared.DrillPBError;
+
+/**
+ * Wraps a DrillPBError object so we don't need to rebuilt it multiple times when sending it to the client. It also
+ * gives access to the original exception className and message.
+ */
+public class DrillRemoteException extends DrillUserException {
+
+  private final DrillPBError error;
+
+  public DrillRemoteException(DrillPBError error) {
+    super(null, "Drill Remote Exception", null);
+    this.error = error;
+  }
+
+  @Override
+  public String getMessage() {
+    return error.getMessage(); // we don't want super class to generate the error message
+  }
+
+  @Override
+  public DrillPBError getOrCreatePBError(boolean verbose) {
+    return error;
+  }
+}

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/common/src/main/java/org/apache/drill/common/exceptions/DrillUserException.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/drill/common/exceptions/DrillUserException.java b/common/src/main/java/org/apache/drill/common/exceptions/DrillUserException.java
new file mode 100644
index 0000000..73718ae
--- /dev/null
+++ b/common/src/main/java/org/apache/drill/common/exceptions/DrillUserException.java
@@ -0,0 +1,204 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.common.exceptions;
+
+import org.apache.drill.exec.proto.UserBitShared.DrillPBError;
+
+public class DrillUserException extends DrillRuntimeException {
+
+  /**
+   * Builder class for DrillUserException. You can wrap an existing exception, in this case it will first check if
+   * this exception is, or wraps, a DrillUserException. If it does then the builder will use the user exception as it is
+   * (it will ignore the message passed to the constructor) and will add any additional context information to the
+   * exception's context
+   */
+  public static class Builder extends UserExceptionContext {
+
+    private final Throwable cause;
+    private final String message;
+    private final DrillPBError.ErrorType errorType;
+
+    private final DrillUserException uex;
+
+    /**
+     * builds a system error that wrap an existing exception. If the exception is, or wraps, a DrillUserException it
+     * won't be converted to a system error.
+     *
+     * We should never need to call this, it will be done automatically before the exception is sent to the client.
+     *
+     * @param cause exception to wrap into a system error
+     */
+    Builder(Throwable cause) {
+      this(DrillPBError.ErrorType.SYSTEM, cause);
+    }
+
+    /**
+     * builds a new user exception of the specified type, with a defined error message
+     *
+     * @param errorType user exception's type
+     * @param format A format string
+     * @param args Arguments referenced by the format specifiers in the format string.
+     */
+    public Builder(DrillPBError.ErrorType errorType, String format, Object... args) {
+      this(errorType, null, format, args);
+    }
+
+    /**
+     * wraps an existing exception inside a user exception. If the exception is, or wraps, a user exception
+     * already, the builder will extract the original user exception and use it instead. If the builder creates a new
+     * user exception it will use the passed exception message, otherwise the builder won't change the message of the
+     * exception
+     *
+     * @param errorType user exception type that should be created if the passed exception isn't, or doesn't wrap a user exception
+     * @param cause exception to wrap inside a user exception
+     */
+    public Builder(DrillPBError.ErrorType errorType, Throwable cause) {
+      this(errorType, cause, null);
+    }
+
+    /**
+     * wraps an existing exception inside a user exception. If the exception is, or wraps, a user exception
+     * already, the builder will extract the original user exception and use it instead.
+     * If the builder creates a new user exception it will use the passed exception message, otherwise the builder
+     * won't change the message of the exception and will add the passed message to the context instead
+     *
+     * @param errorType user exception type that should be created if the passed exception isn't, or doesn't wrap a user exception
+     * @param cause exception to wrap inside a user exception
+     * @param format A format string
+     * @param args Arguments referenced by the format specifiers in the format string.
+     */
+    public Builder(DrillPBError.ErrorType errorType, Throwable cause, String format, Object... args) {
+      super(ErrorHelper.getExceptionContextOrNew(cause));
+      this.cause = cause;
+
+      if (format == null) {
+        this.message = cause != null ? cause.getMessage() : null;
+      } else {
+        this.message = String.format(format, args);
+      }
+
+      //TODO handle the improbable case where cause is a SYSTEM exception ?
+      uex = ErrorHelper.findWrappedUserException(cause);
+      if (uex != null) {
+        this.errorType = null;
+        if (format != null) {
+          // we won't change the exception's message, so add it to the context
+          add(this.message);
+        }
+      } else {
+        // we will create a new user exception
+        this.errorType = errorType;
+      }
+    }
+
+    public DrillUserException build() {
+
+      if (uex != null) {
+        return uex;
+      }
+
+      return new DrillUserException(this);
+    }
+  }
+
+  private final DrillPBError.ErrorType errorType;
+
+  private final UserExceptionContext context;
+
+  protected DrillUserException(DrillPBError.ErrorType errorType, String message, Throwable cause) {
+    super(message, cause);
+
+    this.errorType = errorType;
+    this.context = new UserExceptionContext();
+  }
+
+  private DrillUserException(Builder builder) {
+    super(builder.message, builder.cause);
+    this.errorType = builder.errorType;
+    this.context = builder;
+  }
+
+  public UserExceptionContext getContext() {
+    return context;
+  }
+
+  /**
+   * generates the message that will be displayed to the client without the stack trace.
+   *
+   * @return non verbose error message
+   */
+  @Override
+  public String getMessage() {
+    return generateMessage();
+  }
+
+  /**
+   *
+   * @return the error message that was passed to the builder
+   */
+  public String getOriginalMessage() {
+    return super.getMessage();
+  }
+
+  /**
+   * generates the message that will be displayed to the client. The message also contains the stack trace.
+   *
+   * @return verbose error message
+   */
+  public String getVerboseMessage() {
+    return generateMessage() + "\n\n" + ErrorHelper.buildCausesMessage(getCause());
+  }
+
+  /**
+   * returns or creates a DrillPBError object corresponding to this user exception.
+   *
+   * @param verbose should the error object contain the verbose error message ?
+   * @return protobuf error object
+   */
+  public DrillPBError getOrCreatePBError(boolean verbose) {
+    String message = verbose ? getVerboseMessage() : getMessage();
+
+    DrillPBError.Builder builder = DrillPBError.newBuilder();
+    builder.setErrorType(errorType);
+    builder.setErrorId(context.getErrorId());
+    if (context.getEndpoint() != null) {
+      builder.setEndpoint(context.getEndpoint());
+    }
+    builder.setMessage(message);
+
+    if (getCause() != null) {
+      // some unit tests use this information to make sure a specific exception was thrown in the server
+      builder.setException(ErrorHelper.getWrapper(getCause()));
+    }
+    return builder.build();
+  }
+
+  /**
+   * Generates a user error message that has the following structure:
+   * ERROR TYPE: ERROR_MESSAGE
+   * CONTEXT
+   * [ERROR_ID on DRILLBIT_IP:DRILLBIT_USER_PORT]
+   *
+   * @return generated user error message
+   */
+  private String generateMessage() {
+    return errorType + " ERROR: " + super.getMessage() + "\n" +
+      context.generateContextMessage();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/common/src/main/java/org/apache/drill/common/exceptions/ErrorHelper.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/drill/common/exceptions/ErrorHelper.java b/common/src/main/java/org/apache/drill/common/exceptions/ErrorHelper.java
new file mode 100644
index 0000000..1dc4eb5
--- /dev/null
+++ b/common/src/main/java/org/apache/drill/common/exceptions/ErrorHelper.java
@@ -0,0 +1,186 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.common.exceptions;
+
+import org.apache.drill.exec.proto.UserBitShared.ExceptionWrapper;
+import org.apache.drill.exec.proto.UserBitShared.StackTraceElementWrapper;
+
+import java.util.regex.Pattern;
+
+/**
+ * Utility class that handles error message generation from protobuf error objects.
+ */
+public class ErrorHelper {
+
+  private final static Pattern IGNORE= Pattern.compile("^(sun|com\\.sun|java).*");
+
+  /**
+   * Wraps the exception into a SYSTEM ERROR if it's not already a DrillUserException, or if it's not wrapping a
+   * DrillUserException
+   * @param ex exception to wrap
+   * @return user exception
+   */
+  public static DrillUserException wrap(final Throwable ex) {
+    return new DrillUserException.Builder(ex).build();
+  }
+
+  /**
+   * returns the user exception context for DrillUserExceptions(s) even if they are wrapped multiple times. If no
+   * DrillUserException is found, it will create a new one.
+   * This is useful if we want to add context to user exception before re-throwing it. For all other exception the
+   * context will be discarded.
+   *
+   * @param ex exception we are trying to get the context for
+   * @return user exception context
+   */
+  public static UserExceptionContext getExceptionContextOrNew(final Throwable ex) {
+    DrillUserException uex = findWrappedUserException(ex);
+    if (uex != null) {
+      //TODO if uex is SYSTEM exception the calling code will be able to add context information to it. Do we want this ?
+      return uex.getContext();
+    }
+
+    return new UserExceptionContext();
+  }
+
+  static String buildCausesMessage(final Throwable t) {
+
+    StringBuilder sb = new StringBuilder();
+    Throwable ex = t;
+    boolean cause = false;
+    while(ex != null){
+
+      sb.append("  ");
+
+      if(cause){
+        sb.append("Caused By ");
+      }
+
+      sb.append("(");
+      sb.append(ex.getClass().getCanonicalName());
+      sb.append(") ");
+      sb.append(ex.getMessage());
+      sb.append("\n");
+
+      for(StackTraceElement st : ex.getStackTrace()){
+        sb.append("    ");
+        sb.append(st.getClassName());
+        sb.append('.');
+        sb.append(st.getMethodName());
+        sb.append("():");
+        sb.append(st.getLineNumber());
+        sb.append("\n");
+      }
+      cause = true;
+
+      if(ex.getCause() != null && ex.getCause() != ex){
+        ex = ex.getCause();
+      } else {
+        ex = null;
+      }
+    }
+
+    return sb.toString();
+  }
+
+  static ExceptionWrapper getWrapper(Throwable ex) {
+    return getWrapperBuilder(ex).build();
+  }
+
+  private static ExceptionWrapper.Builder getWrapperBuilder(Throwable ex) {
+    return getWrapperBuilder(ex, false);
+  }
+
+  private static ExceptionWrapper.Builder getWrapperBuilder(Throwable ex, boolean includeAllStack) {
+    ExceptionWrapper.Builder ew = ExceptionWrapper.newBuilder();
+    if(ex.getMessage() != null) {
+      ew.setMessage(ex.getMessage());
+    }
+    ew.setExceptionClass(ex.getClass().getCanonicalName());
+    boolean isHidden = false;
+    StackTraceElement[] stackTrace = ex.getStackTrace();
+    for(int i = 0; i < stackTrace.length; i++){
+      StackTraceElement ele = ex.getStackTrace()[i];
+      if(include(ele, includeAllStack)){
+        if(isHidden){
+          isHidden = false;
+        }
+        ew.addStackTrace(getSTWrapper(ele));
+      }else{
+        if(!isHidden){
+          isHidden = true;
+          ew.addStackTrace(getEmptyST());
+        }
+      }
+
+    }
+
+    if(ex.getCause() != null && ex.getCause() != ex){
+      ew.setCause(getWrapper(ex.getCause()));
+    }
+    return ew;
+  }
+
+  private static boolean include(StackTraceElement ele, boolean includeAllStack) {
+    return includeAllStack || !(IGNORE.matcher(ele.getClassName()).matches());
+  }
+
+  private static StackTraceElementWrapper.Builder getSTWrapper(StackTraceElement ele) {
+    StackTraceElementWrapper.Builder w = StackTraceElementWrapper.newBuilder();
+    w.setClassName(ele.getClassName());
+    if(ele.getFileName() != null) {
+      w.setFileName(ele.getFileName());
+    }
+    w.setIsNativeMethod(ele.isNativeMethod());
+    w.setLineNumber(ele.getLineNumber());
+    w.setMethodName(ele.getMethodName());
+    return w;
+  }
+
+  private static StackTraceElementWrapper.Builder getEmptyST() {
+    StackTraceElementWrapper.Builder w = StackTraceElementWrapper.newBuilder();
+    w.setClassName("...");
+    w.setIsNativeMethod(false);
+    w.setLineNumber(0);
+    w.setMethodName("...");
+    return w;
+  }
+
+  /**
+   * searches for a DrillUserException wrapped inside the exception
+   * @param ex exception
+   * @return null if exception is null or no DrillUserException was found
+   */
+  static DrillUserException findWrappedUserException(Throwable ex) {
+    if (ex == null) {
+      return null;
+    }
+
+    Throwable cause = ex;
+    while (!(cause instanceof DrillUserException)) {
+      if (cause.getCause() != null && cause.getCause() != cause) {
+        cause = cause.getCause();
+      } else {
+        return null;
+      }
+    }
+
+    return (DrillUserException) cause;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/common/src/main/java/org/apache/drill/common/exceptions/UserExceptionContext.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/drill/common/exceptions/UserExceptionContext.java b/common/src/main/java/org/apache/drill/common/exceptions/UserExceptionContext.java
new file mode 100644
index 0000000..ef7d486
--- /dev/null
+++ b/common/src/main/java/org/apache/drill/common/exceptions/UserExceptionContext.java
@@ -0,0 +1,148 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.common.exceptions;
+
+import org.apache.drill.exec.proto.CoordinationProtos;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * Holds context information about a DrillUserException. We can add structured context information that will be used
+ * to generate the error message displayed to the client. We can also specify which context information should only
+ * be displayed in verbose mode
+ */
+public class UserExceptionContext {
+
+  private final String errorId;
+  private final List<String> contextList;
+
+  private CoordinationProtos.DrillbitEndpoint endpoint;
+
+  UserExceptionContext() {
+    errorId = UUID.randomUUID().toString();
+    contextList = new ArrayList<>();
+  }
+
+  UserExceptionContext(UserExceptionContext context) {
+    this.errorId = context.errorId;
+    this.contextList = context.contextList;
+    this.endpoint = context.endpoint;
+  }
+  /**
+   * adds a context line to the bottom of the context list
+   * @param context context line
+   */
+  public UserExceptionContext add(String context) {
+    contextList.add(context);
+    return this;
+  }
+
+  public UserExceptionContext add(CoordinationProtos.DrillbitEndpoint endpoint) {
+    //TODO should we allos the endpoint to change once set ?
+    this.endpoint = endpoint;
+    return this;
+  }
+
+  /**
+   * adds an int to the bottom of the context list
+   * @param context context prefix string
+   * @param value int value
+   */
+  public UserExceptionContext add(String context, long value) {
+    add(context + ": " + value);
+    return this;
+  }
+
+  /**
+   * adds a double to the bottom of the context list
+   * @param context context prefix string
+   * @param value double value
+   */
+  public UserExceptionContext add(String context, double value) {
+    add(context + ": " + value);
+    return this;
+  }
+
+  /**
+   * adds a context line at the top of the context list
+   * @param context context line
+   */
+  public UserExceptionContext push(String context) {
+    contextList.add(0, context);
+    return this;
+  }
+
+  /**
+   * adds an int at the top of the context list
+   * @param context context prefix string
+   * @param value int value
+   */
+  public UserExceptionContext push(String context, long value) {
+    push(context + ": " + value);
+    return this;
+  }
+
+  /**
+   * adds a double at the top of the context list
+   * @param context context prefix string
+   * @param value double value
+   */
+  public UserExceptionContext push(String context, double value) {
+    push(context + ": " + value);
+    return this;
+  }
+
+  String getErrorId() {
+    return errorId;
+  }
+
+  CoordinationProtos.DrillbitEndpoint getEndpoint() {
+    return endpoint;
+  }
+
+  /**
+   * generate a context message
+   * @return string containing all context information concatenated
+   */
+  String generateContextMessage() {
+    StringBuilder sb = new StringBuilder();
+
+    for (String context : contextList) {
+      sb.append(context).append("\n");
+    }
+
+    if (errorId != null || endpoint != null) {
+      // add identification infos
+      sb.append("\n[");
+      if (errorId != null) {
+        sb.append(errorId).append(" ");
+      }
+      if(endpoint != null) {
+        sb.append("on ")
+          .append(endpoint.getAddress())
+          .append(":")
+          .append(endpoint.getUserPort());
+      }
+      sb.append("]\n");
+    }
+
+    return sb.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/common/src/test/java/org/apache/drill/common/exceptions/TestDrillUserException.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/drill/common/exceptions/TestDrillUserException.java b/common/src/test/java/org/apache/drill/common/exceptions/TestDrillUserException.java
new file mode 100644
index 0000000..7b19d55
--- /dev/null
+++ b/common/src/test/java/org/apache/drill/common/exceptions/TestDrillUserException.java
@@ -0,0 +1,130 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.common.exceptions;
+
+import org.apache.drill.exec.proto.UserBitShared.DrillPBError;
+import org.apache.drill.exec.proto.UserBitShared.DrillPBError.ErrorType;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test various use cases around creating user exceptions
+ */
+public class TestDrillUserException {
+
+  private Exception wrap(DrillUserException uex, int numWraps) {
+    Exception ex = uex;
+    for (int i = 0; i < numWraps; i++) {
+      ex = new Exception("wrap #" + (i+1), ex);
+    }
+
+    return ex;
+  }
+
+  // make sure system exceptions are created properly
+  @Test
+  public void testBuildSystemException() {
+    try {
+      throw new DrillUserException.Builder(new RuntimeException("this is an exception")).build();
+    } catch (DrillUserException ex) {
+      DrillPBError error = ex.getOrCreatePBError(true);
+      Assert.assertEquals(ErrorType.SYSTEM, error.getErrorType());
+    }
+  }
+
+  @Test
+  public void testBuildUserExceptionWithMessage() {
+    String message = "Test message";
+
+    DrillUserException uex = new DrillUserException.Builder(ErrorType.DATA_WRITE, message).build();
+    DrillPBError error = uex.getOrCreatePBError(false);
+
+    Assert.assertEquals(ErrorType.DATA_WRITE, error.getErrorType());
+    Assert.assertEquals(message, uex.getOriginalMessage());
+  }
+
+  @Test
+  public void testBuildUserExceptionWithCause() {
+    String message = "Test message";
+
+    DrillUserException uex = new DrillUserException.Builder(ErrorType.DATA_WRITE, new RuntimeException(message)).build();
+    DrillPBError error = uex.getOrCreatePBError(false);
+
+    // cause message should be used
+    Assert.assertEquals(ErrorType.DATA_WRITE, error.getErrorType());
+    Assert.assertEquals(message, uex.getOriginalMessage());
+  }
+
+  @Test
+  public void testBuildUserExceptionWithCauseAndMessage() {
+    String messageA = "Test message A";
+    String messageB = "Test message B";
+
+    DrillUserException uex = new DrillUserException.Builder(ErrorType.DATA_WRITE, new RuntimeException(messageA), messageB).build();
+    DrillPBError error = uex.getOrCreatePBError(false);
+
+    // passed message should override the cause message
+    Assert.assertEquals(ErrorType.DATA_WRITE, error.getErrorType());
+    Assert.assertFalse(error.getMessage().contains(messageA)); // messageA should not be part of the context
+    Assert.assertEquals(messageB, uex.getOriginalMessage());
+  }
+
+  @Test
+  public void testBuildUserExceptionWithUserExceptionCauseAndMessage() {
+    String messageA = "Test message A";
+    String messageB = "Test message B";
+
+    DrillUserException original = new DrillUserException.Builder(ErrorType.CONNECTION, messageA).build();
+    DrillUserException uex = new DrillUserException.Builder(ErrorType.DATA_WRITE, wrap(original, 5), messageB).build();
+
+    //builder should return the unwrapped original user exception and not build a new one
+    Assert.assertEquals(original, uex);
+
+    DrillPBError error = uex.getOrCreatePBError(false);
+    Assert.assertEquals(messageA, uex.getOriginalMessage());
+    Assert.assertTrue(error.getMessage().contains(messageB)); // messageA should be part of the context
+  }
+
+  @Test
+  public void testBuildUserExceptionWithFormattedMessage() {
+    String format = "This is test #%d";
+
+    DrillUserException uex = new DrillUserException.Builder(ErrorType.CONNECTION, format, 5).build();
+    DrillPBError error = uex.getOrCreatePBError(false);
+
+    Assert.assertEquals(ErrorType.CONNECTION, error.getErrorType());
+    Assert.assertEquals(String.format(format, 5), uex.getOriginalMessage());
+  }
+
+  // make sure wrapped user exceptions are retrieved properly when calling ErrorHelper.wrap()
+  @Test
+  public void testWrapUserException() {
+    DrillUserException uex = new DrillUserException.Builder(ErrorType.DATA_READ, "this is a data read exception").build();
+
+    Exception wrapped = wrap(uex, 3);
+    Assert.assertEquals(uex, ErrorHelper.wrap(wrapped));
+  }
+
+  @Test
+  public void testEdgeCases() {
+    new DrillUserException.Builder(null).build();
+    new DrillUserException.Builder(ErrorType.DATA_WRITE, null).build().getOrCreatePBError(true);
+    new DrillUserException.Builder(ErrorType.DATA_WRITE, null).build().getOrCreatePBError(true);
+    new DrillUserException.Builder(ErrorType.DATA_WRITE, new RuntimeException(), null).build().getOrCreatePBError(true);
+  }
+}

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/client/DrillClient.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/client/DrillClient.java b/exec/java-exec/src/main/java/org/apache/drill/exec/client/DrillClient.java
index 579cf7d..6555cad 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/client/DrillClient.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/client/DrillClient.java
@@ -33,6 +33,7 @@ import java.util.Vector;
 
 import io.netty.channel.EventLoopGroup;
 import org.apache.drill.common.config.DrillConfig;
+import org.apache.drill.common.exceptions.DrillUserException;
 import org.apache.drill.exec.ExecConstants;
 import org.apache.drill.exec.coord.ClusterCoordinator;
 import org.apache.drill.exec.coord.zk.ZKClusterCoordinator;
@@ -307,9 +308,9 @@ public class DrillClient implements Closeable, ConnectionThrottle {
     }
 
     @Override
-    public void submissionFailed(RpcException ex) {
+    public void submissionFailed(DrillUserException ex) {
       // or  !client.isActive()
-      if (ex instanceof ChannelClosedException) {
+      if (ex.getCause() instanceof ChannelClosedException) {
         if (reconnect()) {
           try {
             client.submitQuery(this, query);

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/client/PrintingResultsListener.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/client/PrintingResultsListener.java b/exec/java-exec/src/main/java/org/apache/drill/exec/client/PrintingResultsListener.java
index 98948af..a11cec0 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/client/PrintingResultsListener.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/client/PrintingResultsListener.java
@@ -22,6 +22,8 @@ import java.util.concurrent.atomic.AtomicInteger;
 
 import io.netty.buffer.DrillBuf;
 import org.apache.drill.common.config.DrillConfig;
+import org.apache.drill.common.exceptions.DrillUserException;
+import org.apache.drill.common.exceptions.ErrorHelper;
 import org.apache.drill.exec.client.QuerySubmitter.Format;
 import org.apache.drill.exec.exception.SchemaChangeException;
 import org.apache.drill.exec.memory.BufferAllocator;
@@ -29,7 +31,6 @@ import org.apache.drill.exec.memory.TopLevelAllocator;
 import org.apache.drill.exec.proto.UserBitShared.QueryId;
 import org.apache.drill.exec.proto.UserBitShared.QueryData;
 import org.apache.drill.exec.record.RecordBatchLoader;
-import org.apache.drill.exec.rpc.RpcException;
 import org.apache.drill.exec.rpc.user.ConnectionThrottle;
 import org.apache.drill.exec.rpc.user.QueryDataBatch;
 import org.apache.drill.exec.rpc.user.UserResultsListener;
@@ -42,7 +43,7 @@ public class PrintingResultsListener implements UserResultsListener {
   Format format;
   int    columnWidth;
   BufferAllocator allocator;
-  volatile Exception exception;
+  volatile DrillUserException exception;
   QueryId queryId;
 
   public PrintingResultsListener(DrillConfig config, Format format, int columnWidth) {
@@ -53,7 +54,7 @@ public class PrintingResultsListener implements UserResultsListener {
   }
 
   @Override
-  public void submissionFailed(RpcException ex) {
+  public void submissionFailed(DrillUserException ex) {
     exception = ex;
     System.out.println("Exception (no rows returned): " + ex );
     latch.countDown();
@@ -76,7 +77,7 @@ public class PrintingResultsListener implements UserResultsListener {
       try {
         loader.load(header.getDef(), data);
       } catch (SchemaChangeException e) {
-        submissionFailed(new RpcException(e));
+        submissionFailed(ErrorHelper.wrap(e));
       }
 
       switch(format) {

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContext.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContext.java b/exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContext.java
index da2229c..8c402e8 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContext.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/ops/FragmentContext.java
@@ -18,7 +18,6 @@
 package org.apache.drill.exec.ops;
 
 import com.google.common.base.Preconditions;
-import io.netty.buffer.ByteBuf;
 import io.netty.buffer.DrillBuf;
 
 import java.io.IOException;
@@ -30,6 +29,8 @@ import net.hydromatic.optiq.jdbc.SimpleOptiqSchema;
 
 import org.apache.drill.common.DeferredException;
 import org.apache.drill.common.config.DrillConfig;
+import org.apache.drill.common.exceptions.DrillUserException;
+import org.apache.drill.common.exceptions.ErrorHelper;
 import org.apache.drill.common.exceptions.ExecutionSetupException;
 import org.apache.drill.exec.exception.ClassTransformationException;
 import org.apache.drill.exec.expr.ClassGenerator;
@@ -37,18 +38,14 @@ import org.apache.drill.exec.expr.CodeGenerator;
 import org.apache.drill.exec.expr.fn.FunctionImplementationRegistry;
 import org.apache.drill.exec.memory.BufferAllocator;
 import org.apache.drill.exec.memory.OutOfMemoryException;
-import org.apache.drill.exec.physical.impl.materialize.QueryWritableBatch;
 import org.apache.drill.exec.planner.physical.PlannerSettings;
 import org.apache.drill.exec.proto.BitControl.PlanFragment;
 import org.apache.drill.exec.proto.CoordinationProtos.DrillbitEndpoint;
 import org.apache.drill.exec.proto.ExecProtos.FragmentHandle;
 import org.apache.drill.exec.proto.GeneralRPCProtos.Ack;
-import org.apache.drill.exec.record.FragmentWritableBatch;
-import org.apache.drill.exec.rpc.DrillRpcFuture;
 import org.apache.drill.exec.rpc.RpcException;
 import org.apache.drill.exec.rpc.RpcOutcomeListener;
 import org.apache.drill.exec.rpc.control.ControlTunnel;
-import org.apache.drill.exec.rpc.data.DataTunnel;
 import org.apache.drill.exec.rpc.user.UserServer.UserClientConnection;
 import org.apache.drill.exec.server.DrillbitContext;
 import org.apache.drill.exec.server.options.FragmentOptionManager;
@@ -150,10 +147,16 @@ public class FragmentContext implements AutoCloseable, UdfUtilities {
 
   public void fail(Throwable cause) {
     final FragmentHandle fragmentHandle = fragment.getHandle();
+
+    DrillUserException dse = ErrorHelper.wrap(cause);
+    dse.getContext().add(getIdentity());
+
+    // log the error id
     logger.error("Fragment Context received failure -- Fragment: {}:{}",
-      fragmentHandle.getMajorFragmentId(), fragmentHandle.getMinorFragmentId(), cause);
+      fragmentHandle.getMajorFragmentId(), fragmentHandle.getMinorFragmentId(), dse);
+
     setState(FragmentContextState.FAILED);
-    deferredException.addThrowable(cause);
+    deferredException.addThrowable(dse);
   }
 
   public void cancel() {

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/ScreenCreator.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/ScreenCreator.java b/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/ScreenCreator.java
index 6b3caf4..80cbd81 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/ScreenCreator.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/ScreenCreator.java
@@ -38,8 +38,6 @@ import com.google.common.base.Preconditions;
 public class ScreenCreator implements RootCreator<Screen>{
   private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ScreenCreator.class);
 
-
-
   @Override
   public RootExec getRoot(FragmentContext context, Screen config, List<RecordBatch> children) throws ExecutionSetupException {
     Preconditions.checkNotNull(children);

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillSqlWorker.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillSqlWorker.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillSqlWorker.java
index b98778d..7892999 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillSqlWorker.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillSqlWorker.java
@@ -18,7 +18,6 @@
 package org.apache.drill.exec.planner.sql;
 
 import java.io.IOException;
-import java.io.Reader;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -30,6 +29,7 @@ import net.hydromatic.optiq.tools.RelConversionException;
 import net.hydromatic.optiq.tools.RuleSet;
 import net.hydromatic.optiq.tools.ValidationException;
 
+import org.apache.drill.common.exceptions.DrillUserException;
 import org.apache.drill.exec.ops.QueryContext;
 import org.apache.drill.exec.physical.PhysicalPlan;
 import org.apache.drill.exec.planner.cost.DrillCostBase;
@@ -44,6 +44,7 @@ import org.apache.drill.exec.planner.sql.handlers.SqlHandlerConfig;
 import org.apache.drill.exec.planner.sql.parser.DrillSqlCall;
 import org.apache.drill.exec.planner.sql.parser.SqlCreateTable;
 import org.apache.drill.exec.planner.sql.parser.impl.DrillParserWithCompoundIdConverter;
+import org.apache.drill.exec.proto.UserBitShared.DrillPBError.ErrorType;
 import org.apache.drill.exec.store.StoragePluginRegistry;
 import org.apache.drill.exec.util.Pointer;
 import org.apache.drill.exec.work.foreman.ForemanSetupException;
@@ -56,10 +57,8 @@ import org.eigenbase.relopt.RelTraitDef;
 import org.eigenbase.relopt.hep.HepPlanner;
 import org.eigenbase.relopt.hep.HepProgramBuilder;
 import org.eigenbase.sql.SqlNode;
-import org.eigenbase.sql.parser.SqlAbstractParserImpl;
 import org.eigenbase.sql.parser.SqlParseException;
 import org.eigenbase.sql.parser.SqlParser;
-import org.eigenbase.sql.parser.SqlParserImplFactory;
 
 public class DrillSqlWorker {
   static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(DrillSqlWorker.class);
@@ -105,8 +104,8 @@ public class DrillSqlWorker {
   private RuleSet[] getRules(QueryContext context) {
     StoragePluginRegistry storagePluginRegistry = context.getStorage();
     RuleSet drillLogicalRules = DrillRuleSets.mergedRuleSets(
-        DrillRuleSets.getDrillBasicRules(context),
-        DrillRuleSets.getDrillUserConfigurableLogicalRules(context));
+      DrillRuleSets.getDrillBasicRules(context),
+      DrillRuleSets.getDrillUserConfigurableLogicalRules(context));
     RuleSet drillPhysicalMem = DrillRuleSets.mergedRuleSets(
         DrillRuleSets.getPhysicalRules(context),
         storagePluginRegistry.getStoragePluginRuleSet());
@@ -152,14 +151,13 @@ public class DrillSqlWorker {
       handler = new DefaultSqlHandler(config, textPlan);
     }
 
-    try{
+    try {
       return handler.getPlan(sqlNode);
-    }catch(ValidationException e){
-      throw new QueryInputException("Failure validating SQL. " + e.getMessage(), e);
+    } catch(ValidationException e) {
+      String errorMessage = e.getCause() != null ? e.getCause().getMessage() : e.getMessage();
+      throw new DrillUserException.Builder(ErrorType.PARSE, e, errorMessage).build();
     } catch (IOException | RelConversionException e) {
       throw new QueryInputException("Failure handling SQL.", e);
     }
-
   }
-
 }

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/CoordinationQueue.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/CoordinationQueue.java b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/CoordinationQueue.java
index 0016d6a..ad5002e 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/CoordinationQueue.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/CoordinationQueue.java
@@ -23,6 +23,7 @@ import io.netty.channel.ChannelFuture;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
+import org.apache.drill.common.exceptions.DrillRemoteException;
 import org.apache.drill.exec.proto.UserBitShared.DrillPBError;
 
 /**
@@ -150,7 +151,7 @@ public class CoordinationQueue {
     // logger.debug("Updating failed future.");
     try {
       RpcOutcome<?> rpc = removeFromMap(coordinationId);
-      rpc.setException(new RemoteRpcException(failure));
+      rpc.setException(new DrillRemoteException(failure));
     } catch(Exception ex) {
       logger.warn("Failed to remove from map.  Not a problem since we were updating on failed future.", ex);
     }

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RemoteRpcException.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RemoteRpcException.java b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RemoteRpcException.java
deleted file mode 100644
index 14ea873..0000000
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RemoteRpcException.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.drill.exec.rpc;
-
-import org.apache.drill.exec.proto.UserBitShared.DrillPBError;
-import org.apache.drill.exec.work.ErrorHelper;
-
-public class RemoteRpcException extends RpcException{
-  static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(RemoteRpcException.class);
-
-  private final DrillPBError failure;
-
-  public RemoteRpcException(DrillPBError failure) {
-    super(ErrorHelper.getErrorMessage(failure, false));
-    this.failure = failure;
-  }
-
-  @Override
-  public DrillPBError getRemoteError() {
-    return failure;
-  }
-
-  @Override
-  public boolean isRemote() {
-    return true;
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RpcBus.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RpcBus.java b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RpcBus.java
index b974963..79232c9 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RpcBus.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/RpcBus.java
@@ -30,9 +30,10 @@ import java.io.Closeable;
 import java.util.Arrays;
 import java.util.List;
 
+import org.apache.drill.common.exceptions.DrillUserException;
+import org.apache.drill.common.exceptions.ErrorHelper;
 import org.apache.drill.exec.proto.GeneralRPCProtos.RpcMode;
 import org.apache.drill.exec.proto.UserBitShared.DrillPBError;
-import org.apache.drill.exec.work.ErrorHelper;
 
 import com.google.common.base.Preconditions;
 import com.google.protobuf.Internal.EnumLite;
@@ -193,8 +194,13 @@ public abstract class RpcBus<T extends EnumLite, C extends RemoteConnection> imp
         try {
           handle(connection, msg.rpcType, msg.pBody, msg.dBody, sender);
         } catch(UserRpcException e){
-          DrillPBError error = ErrorHelper.logAndConvertError(e.getEndpoint(), e.getUserMessage(), e, logger);
-          OutboundRpcMessage outMessage = new OutboundRpcMessage(RpcMode.RESPONSE_FAILURE, 0, msg.coordinationId, error);
+          DrillUserException uex = ErrorHelper.wrap(e);
+          uex.getContext().add(e.getEndpoint());
+
+          logger.error("Unexpected Error while handling request message", e);
+
+          OutboundRpcMessage outMessage = new OutboundRpcMessage(RpcMode.RESPONSE_FAILURE, 0, msg.coordinationId,
+            uex.getOrCreatePBError(false));
           if (RpcConstants.EXTRA_DEBUGGING) {
             logger.debug("Adding message to outbound buffer. {}", outMessage);
           }

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/QueryResultHandler.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/QueryResultHandler.java b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/QueryResultHandler.java
index a1be83b..a03e2c0 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/QueryResultHandler.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/QueryResultHandler.java
@@ -23,7 +23,9 @@ import io.netty.buffer.DrillBuf;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ConcurrentMap;
 
-import org.apache.drill.exec.proto.UserBitShared;
+import org.apache.drill.common.exceptions.DrillRemoteException;
+import org.apache.drill.common.exceptions.DrillUserException;
+import org.apache.drill.common.exceptions.ErrorHelper;
 import org.apache.drill.exec.proto.UserBitShared.QueryId;
 import org.apache.drill.exec.proto.UserBitShared.QueryResult;
 import org.apache.drill.exec.proto.UserBitShared.QueryData;
@@ -107,8 +109,7 @@ public class QueryResultHandler {
       if (isFailureResult) {
         // Failure case--pass on via submissionFailed(...).
 
-        String message = buildErrorMessage(queryResult);
-        resultsListener.submissionFailed(new RpcException(message));
+        resultsListener.submissionFailed(new DrillRemoteException(queryResult.getError(0)));
         // Note: Listener is removed in finally below.
       } else if (isTerminalResult) {
         // A successful completion/canceled case--pass on via resultArrived
@@ -116,7 +117,7 @@ public class QueryResultHandler {
         try {
           resultsListener.queryCompleted();
         } catch ( Exception e ) {
-          resultsListener.submissionFailed(new RpcException(e));
+          resultsListener.submissionFailed(ErrorHelper.wrap(e));
         }
       } else {
         logger.warn("queryState {} was ignored", queryState);
@@ -157,7 +158,7 @@ public class QueryResultHandler {
       // That releases batch if successful.
     } catch ( Exception e ) {
       batch.release();
-      resultsListener.submissionFailed(new RpcException(e));
+      resultsListener.submissionFailed(ErrorHelper.wrap(e));
     }
   }
 
@@ -189,18 +190,9 @@ public class QueryResultHandler {
     return resultsListener;
   }
 
-  protected String buildErrorMessage(QueryResult result) {
-    StringBuilder sb = new StringBuilder();
-    for (UserBitShared.DrillPBError error : result.getErrorList()) {
-      sb.append(error.getMessage());
-      sb.append("\n");
-    }
-    return sb.toString();
-  }
-
   private void failAll() {
     for (UserResultsListener l : queryIdToResultsListenersMap.values()) {
-      l.submissionFailed(new RpcException("Received result without QueryId"));
+      l.submissionFailed(ErrorHelper.wrap(new RpcException("Received result without QueryId")));
     }
   }
 
@@ -208,7 +200,7 @@ public class QueryResultHandler {
 
     private ConcurrentLinkedQueue<QueryDataBatch> results = Queues.newConcurrentLinkedQueue();
     private volatile boolean finished = false;
-    private volatile RpcException ex;
+    private volatile DrillUserException ex;
     private volatile UserResultsListener output;
     private volatile ConnectionThrottle throttle;
 
@@ -253,7 +245,7 @@ public class QueryResultHandler {
     }
 
     @Override
-    public void submissionFailed(RpcException ex) {
+    public void submissionFailed(DrillUserException ex) {
       finished = true;
       synchronized (this) {
         if (output == null) {
@@ -284,7 +276,7 @@ public class QueryResultHandler {
 
     @Override
     public void failed(RpcException ex) {
-      resultsListener.submissionFailed(ex);
+      resultsListener.submissionFailed(ErrorHelper.wrap(ex));
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/UserResultsListener.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/UserResultsListener.java b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/UserResultsListener.java
index 934a094..b9f742c 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/UserResultsListener.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/UserResultsListener.java
@@ -17,8 +17,8 @@
  */
 package org.apache.drill.exec.rpc.user;
 
+import org.apache.drill.common.exceptions.DrillUserException;
 import org.apache.drill.exec.proto.UserBitShared.QueryId;
-import org.apache.drill.exec.rpc.RpcException;
 
 public interface UserResultsListener {
 
@@ -33,7 +33,7 @@ public interface UserResultsListener {
    * {@link #dataArrived(QueryDataBatch, ConnectionThrottle) dataArrived()} throws an exception
    * @param ex exception describing the cause of the failure
    */
-  void submissionFailed(RpcException ex);
+  void submissionFailed(DrillUserException ex);
 
   /**
    * The query has completed (successsful completion or cancellation). The listener will not receive any other

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryWrapper.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryWrapper.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryWrapper.java
index fbbf0b8..8415440 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryWrapper.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryWrapper.java
@@ -30,6 +30,7 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import org.apache.drill.common.config.DrillConfig;
+import org.apache.drill.common.exceptions.DrillUserException;
 import org.apache.drill.exec.client.DrillClient;
 import org.apache.drill.exec.coord.ClusterCoordinator;
 import org.apache.drill.exec.exception.SchemaChangeException;
@@ -37,7 +38,6 @@ import org.apache.drill.exec.memory.BufferAllocator;
 import org.apache.drill.exec.proto.UserBitShared;
 import org.apache.drill.exec.record.RecordBatchLoader;
 import org.apache.drill.exec.record.VectorWrapper;
-import org.apache.drill.exec.rpc.RpcException;
 import org.apache.drill.exec.rpc.user.ConnectionThrottle;
 import org.apache.drill.exec.rpc.user.QueryDataBatch;
 import org.apache.drill.exec.rpc.user.UserResultsListener;
@@ -118,7 +118,7 @@ public class QueryWrapper {
 
 
   private static class Listener implements UserResultsListener {
-    private volatile Exception exception;
+    private volatile DrillUserException exception;
     private final CountDownLatch latch = new CountDownLatch(1);
     private final BufferAllocator allocator;
     public final List<Map<String, String>> results = Lists.newArrayList();
@@ -129,7 +129,7 @@ public class QueryWrapper {
     }
 
     @Override
-    public void submissionFailed(RpcException ex) {
+    public void submissionFailed(DrillUserException ex) {
       exception = ex;
       logger.error("Query Failed", ex);
       latch.countDown();

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/store/easy/json/JSONRecordReader.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/store/easy/json/JSONRecordReader.java b/exec/java-exec/src/main/java/org/apache/drill/exec/store/easy/json/JSONRecordReader.java
index cc7cb83..91e0b21 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/store/easy/json/JSONRecordReader.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/store/easy/json/JSONRecordReader.java
@@ -22,7 +22,7 @@ import java.io.InputStream;
 import java.util.List;
 
 import com.google.common.collect.ImmutableList;
-import org.apache.drill.common.exceptions.DrillRuntimeException;
+import org.apache.drill.common.exceptions.DrillUserException;
 import org.apache.drill.common.exceptions.ExecutionSetupException;
 import org.apache.drill.common.expression.SchemaPath;
 import org.apache.drill.exec.ExecConstants;
@@ -30,6 +30,7 @@ import org.apache.drill.exec.memory.OutOfMemoryException;
 import org.apache.drill.exec.ops.FragmentContext;
 import org.apache.drill.exec.ops.OperatorContext;
 import org.apache.drill.exec.physical.impl.OutputMutator;
+import org.apache.drill.exec.proto.UserBitShared.DrillPBError.ErrorType;
 import org.apache.drill.exec.store.AbstractRecordReader;
 import org.apache.drill.exec.store.dfs.DrillFileSystem;
 import org.apache.drill.exec.store.easy.json.reader.CountingJsonReader;
@@ -90,14 +91,27 @@ public class JSONRecordReader extends AbstractRecordReader {
     }
   }
 
-  protected void handleAndRaise(String msg, Exception e) {
-    StringBuilder sb = new StringBuilder();
-    sb.append(msg).append(" - In ").append(hadoopPath.toUri().getPath()).append(" parser was at record: ").append(recordCount+1);
+  protected void handleAndRaise(String suffix, Exception e) throws DrillUserException {
+
+    String message = e.getMessage();
+    int columnNr = -1;
+
     if (e instanceof JsonParseException) {
-      JsonParseException ex = JsonParseException.class.cast(e);
-      sb.append(" column: ").append(ex.getLocation().getColumnNr());
+      JsonParseException ex = (JsonParseException) e;
+      message = ex.getOriginalMessage();
+      columnNr = ex.getLocation().getColumnNr();
+    }
+
+    DrillUserException.Builder builder = new DrillUserException.Builder(ErrorType.DATA_READ, e, "%s - %s", suffix, message);
+
+    // add context information
+    builder.add("Filename: " + hadoopPath.toUri().getPath());
+    builder.add("Record", recordCount + 1);
+    if (columnNr != -1) {
+      builder.add("Column", columnNr);
     }
-    throw new DrillRuntimeException(sb.toString(), e);
+
+    throw builder.build();
   }
 
 

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/work/ErrorHelper.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/work/ErrorHelper.java b/exec/java-exec/src/main/java/org/apache/drill/exec/work/ErrorHelper.java
deleted file mode 100644
index 0773d6c..0000000
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/work/ErrorHelper.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.drill.exec.work;
-
-import java.util.UUID;
-import java.util.regex.Pattern;
-
-import org.apache.drill.common.exceptions.DrillException;
-import org.apache.drill.exec.proto.CoordinationProtos.DrillbitEndpoint;
-import org.apache.drill.exec.proto.UserBitShared.DrillPBError;
-import org.apache.drill.exec.proto.UserBitShared.ExceptionWrapper;
-import org.apache.drill.exec.proto.UserBitShared.StackTraceElementWrapper;
-import org.apache.drill.exec.rpc.RemoteRpcException;
-import org.slf4j.Logger;
-
-
-public class ErrorHelper {
-  static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ErrorHelper.class);
-
-  final static Pattern IGNORE= Pattern.compile("^(sun|com\\.sun|java).*");
-
-  /**
-   * Manages message conversion before returning to user.  If the exception is a remote rpc exception, will simply return user friendly message.  Otherwise, will log and return.
-   * TODO: this should really be done client side but we don't currently have any way to maintain session state on the client.
-   *
-   * @param endpoint
-   * @param message
-   * @param t
-   * @param logger
-   * @param verbose
-   * @return
-   */
-  public static DrillPBError logAndConvertMessageError(DrillbitEndpoint endpoint, String message, Throwable t, Logger logger, boolean verbose) {
-
-    DrillPBError baseError = t instanceof RemoteRpcException ? ((RemoteRpcException) t).getRemoteError() : logAndConvertError(endpoint, message, t, logger);
-    String userMessage = getErrorMessage(baseError, verbose);
-    return DrillPBError.newBuilder() //
-      .setEndpoint(baseError.getEndpoint()) //
-      .setErrorId(baseError.getErrorId()) //
-      .setMessage(userMessage) //
-      .build();
-  }
-
-  public static DrillPBError logAndConvertError(DrillbitEndpoint endpoint, String message, Throwable t, Logger logger) {
-    String id = UUID.randomUUID().toString();
-    DrillPBError.Builder builder = DrillPBError.newBuilder();
-    builder.setEndpoint(endpoint);
-    builder.setErrorId(id);
-    if(message != null){
-      builder.setMessage(message);
-    }
-    if(t == null){
-      t = new DrillException("Undefined failure occurred.");
-    }
-    builder.setException(getWrapper(t));
-
-    // record the error to the log for later reference.
-    logger.error("Error {}: {}", id, message, t);
-
-    return builder.build();
-  }
-
-  public static ExceptionWrapper getWrapper(Throwable ex){
-    return getWrapperBuilder(ex).build();
-  }
-
-  public static ExceptionWrapper.Builder getWrapperBuilder(Throwable ex){
-    return getWrapperBuilder(ex, false);
-  }
-
-  public static ExceptionWrapper.Builder getWrapperBuilder(Throwable ex, boolean includeAllStack){
-
-
-
-    ExceptionWrapper.Builder ew = ExceptionWrapper.newBuilder();
-    if(ex.getMessage() != null) {
-      ew.setMessage(ex.getMessage());
-    }
-    ew.setExceptionClass(ex.getClass().getCanonicalName());
-    boolean isHidden = false;
-    StackTraceElementWrapper[] wrappers = new StackTraceElementWrapper[ex.getStackTrace().length];
-    for(int i = 0; i < wrappers.length; i++){
-      StackTraceElement ele = ex.getStackTrace()[i];
-      if(include(ele, includeAllStack)){
-        if(isHidden){
-          isHidden = false;
-        }
-        ew.addStackTrace(getSTWrapper(ele));
-      }else{
-        if(!isHidden){
-          isHidden = true;
-          ew.addStackTrace(getEmptyST());
-        }
-      }
-
-    }
-
-    if(ex.getCause() != null && ex.getCause() != ex){
-      ew.setCause(getWrapper(ex.getCause()));
-    }
-    return ew;
-  }
-
-  private static boolean include(StackTraceElement ele, boolean includeAllStack){
-    if(includeAllStack) {
-      return true;
-    }
-    return !(IGNORE.matcher(ele.getClassName()).matches());
-  }
-
-  private static StackTraceElementWrapper.Builder getEmptyST(){
-    StackTraceElementWrapper.Builder w = StackTraceElementWrapper.newBuilder();
-    w.setClassName("...");
-    w.setIsNativeMethod(false);
-    w.setLineNumber(0);
-    w.setMethodName("...");
-    return w;
-  }
-  public static StackTraceElementWrapper.Builder getSTWrapper(StackTraceElement ele){
-    StackTraceElementWrapper.Builder w = StackTraceElementWrapper.newBuilder();
-    w.setClassName(ele.getClassName());
-    if(ele.getFileName() != null) {
-      w.setFileName(ele.getFileName());
-    }
-    w.setIsNativeMethod(ele.isNativeMethod());
-    w.setLineNumber(ele.getLineNumber());
-    w.setMethodName(ele.getMethodName());
-    return w;
-  }
-
-
-  public static String getErrorMessage(final DrillPBError error, final boolean verbose) {
-
-    String finalMessage = null;
-    ExceptionWrapper ex = error.getException();
-    StringBuilder sb = new StringBuilder();
-
-
-
-    sb //
-      .append("[ ") //
-      .append(error.getErrorId()) //
-      .append(" on ")
-      .append(error.getEndpoint().getAddress())
-      .append(":").append(error.getEndpoint().getUserPort())
-      .append(" ]\n");
-
-    boolean cause = false;
-    while(ex != null){
-
-      if(ex.hasMessage()){
-        finalMessage = ex.getMessage();
-      }
-
-      if(verbose){
-        sb.append("  ");
-
-        if(cause){
-          sb.append("Caused By ");
-        }
-
-        sb.append("(");
-        sb.append(ex.getExceptionClass());
-        sb.append(") ");
-        sb.append(ex.getMessage());
-        sb.append("\n");
-        for(int i = 0; i < ex.getStackTraceCount(); i++){
-          StackTraceElementWrapper st = ex.getStackTrace(i);
-          sb.append("    ");
-          sb.append(st.getClassName());
-          sb.append('.');
-          sb.append(st.getMethodName());
-          sb.append("():");
-          sb.append(st.getLineNumber());
-          sb.append("\n");
-        }
-        cause = true;
-      }
-
-      ex = ex.hasCause() ? ex.getCause() : null;
-
-
-    }
-
-    StringBuilder msg = new StringBuilder();
-
-    if (error.hasMessage()){
-      msg.append(error.getMessage());
-      if(finalMessage != null){
-        msg.append(", ");
-        msg.append(finalMessage);
-        msg.append(' ');
-      }
-    }else if(finalMessage != null){
-      msg.append(finalMessage);
-      msg.append(' ');
-    }else{
-      msg.append("Error ");
-    }
-
-    msg.append(sb);
-
-    return msg.toString();
-  }
-
-  public static void main(String[] args ){
-    DrillPBError e = logAndConvertError(DrillbitEndpoint.newBuilder().setAddress("host1").setControlPort(1234).build(), "RpcFailure", new Exception("Excep 1", new Exception("excep2")), logger);
-    System.out.println(getErrorMessage(e, false));
-    System.out.println("\n\n\n");
-    System.out.println(getErrorMessage(e, true));
-
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/Foreman.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/Foreman.java b/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/Foreman.java
index 23ef0d3..0df5145 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/Foreman.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/Foreman.java
@@ -28,9 +28,10 @@ import java.util.concurrent.TimeUnit;
 
 import com.google.common.base.Preconditions;
 
-import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.drill.common.EventProcessor;
 import org.apache.drill.common.config.DrillConfig;
+import org.apache.drill.common.exceptions.DrillUserException;
+import org.apache.drill.common.exceptions.ErrorHelper;
 import org.apache.drill.common.exceptions.ExecutionSetupException;
 import org.apache.drill.common.logical.LogicalPlan;
 import org.apache.drill.common.logical.PlanProperties.Generator.ResultMode;
@@ -56,7 +57,6 @@ import org.apache.drill.exec.proto.BitControl.PlanFragment;
 import org.apache.drill.exec.proto.CoordinationProtos.DrillbitEndpoint;
 import org.apache.drill.exec.proto.ExecProtos.FragmentHandle;
 import org.apache.drill.exec.proto.GeneralRPCProtos.Ack;
-import org.apache.drill.exec.proto.UserBitShared.DrillPBError;
 import org.apache.drill.exec.proto.UserBitShared.QueryId;
 import org.apache.drill.exec.proto.UserBitShared.QueryResult;
 import org.apache.drill.exec.proto.UserBitShared.QueryResult.QueryState;
@@ -71,7 +71,6 @@ import org.apache.drill.exec.server.options.OptionManager;
 import org.apache.drill.exec.testing.ExceptionInjector;
 import org.apache.drill.exec.util.Pointer;
 import org.apache.drill.exec.work.EndpointListener;
-import org.apache.drill.exec.work.ErrorHelper;
 import org.apache.drill.exec.work.QueryWorkUnit;
 import org.apache.drill.exec.work.WorkManager.WorkerBee;
 import org.apache.drill.exec.work.batch.IncomingBuffers;
@@ -500,7 +499,7 @@ public class Foreman implements Runnable {
    */
   private class ForemanResult implements AutoCloseable {
     private QueryState resultState = null;
-    private Exception resultException = null;
+    private DrillUserException resultException = null;
     private boolean isClosed = false;
 
     /**
@@ -533,7 +532,7 @@ public class Foreman implements Runnable {
       Preconditions.checkState(resultState == null);
 
       resultState = QueryState.FAILED;
-      resultException = exception;
+      addException(exception);
     }
 
     /**
@@ -546,7 +545,8 @@ public class Foreman implements Runnable {
       Preconditions.checkNotNull(exception);
 
       if (resultException == null) {
-        resultException = exception;
+        resultException = ErrorHelper.wrap(exception);
+        resultException.getContext().add(queryContext.getCurrentEndpoint());
       } else {
         resultException.addSuppressed(exception);
       }
@@ -614,9 +614,8 @@ public class Foreman implements Runnable {
           .setQueryId(queryId)
           .setQueryState(resultState);
       if (resultException != null) {
-        final DrillPBError error = ErrorHelper.logAndConvertError(queryContext.getCurrentEndpoint(),
-            ExceptionUtils.getRootCauseMessage(resultException), resultException, logger);
-        resultBuilder.addError(error);
+        boolean verbose = queryContext.getOptions().getOption(ExecConstants.ENABLE_VERBOSE_ERRORS_KEY).bool_val;
+        resultBuilder.addError(resultException.getOrCreatePBError(verbose));
       }
 
       /*

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/QueryManager.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/QueryManager.java b/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/QueryManager.java
index 8626d5b..dc60beb 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/QueryManager.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/QueryManager.java
@@ -24,6 +24,7 @@ import java.util.List;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.apache.drill.common.exceptions.DrillRemoteException;
 import org.apache.drill.common.exceptions.DrillRuntimeException;
 import org.apache.drill.exec.ops.FragmentContext;
 import org.apache.drill.exec.proto.BitControl.FragmentStatus;
@@ -39,7 +40,6 @@ import org.apache.drill.exec.proto.UserBitShared.QueryProfile;
 import org.apache.drill.exec.proto.UserBitShared.QueryResult.QueryState;
 import org.apache.drill.exec.proto.UserProtos.RunQuery;
 import org.apache.drill.exec.proto.helper.QueryIdHelper;
-import org.apache.drill.exec.rpc.RemoteRpcException;
 import org.apache.drill.exec.rpc.RpcException;
 import org.apache.drill.exec.rpc.control.Controller;
 import org.apache.drill.exec.server.DrillbitContext;
@@ -160,7 +160,7 @@ public class QueryManager implements FragmentStatusListener, DrillbitStatusListe
       break;
 
     case FAILED:
-      stateListener.moveToState(QueryState.FAILED, new RemoteRpcException(status.getProfile().getError()));
+      stateListener.moveToState(QueryState.FAILED, new DrillRemoteException(status.getProfile().getError()));
       break;
 
     default:

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/SqlUnsupportedException.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/SqlUnsupportedException.java b/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/SqlUnsupportedException.java
index 2299afa..e372283 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/SqlUnsupportedException.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/work/foreman/SqlUnsupportedException.java
@@ -47,10 +47,10 @@ public abstract class SqlUnsupportedException extends ForemanSetupException {
     super(errorMessage);
   }
 
-  public static void errorMessageToException(String errorMessage) throws SqlUnsupportedException {
+  public static void errorClassNameToException(String errorClassName) throws SqlUnsupportedException {
     UnsupportedOperatorCollector collector = new UnsupportedOperatorCollector();
     for(ExceptionType ex : ExceptionType.values()) {
-      if(errorMessage.startsWith(ex.toString())) {
+      if(errorClassName.endsWith(ex.toString())) {
         collector.setException(ex);
         collector.convertException();
         collector.clean();

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/AbstractStatusReporter.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/AbstractStatusReporter.java b/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/AbstractStatusReporter.java
index 1b0885d..8279876 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/AbstractStatusReporter.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/AbstractStatusReporter.java
@@ -17,13 +17,13 @@
  */
 package org.apache.drill.exec.work.fragment;
 
+import org.apache.drill.common.exceptions.DrillUserException;
 import org.apache.drill.exec.ExecConstants;
 import org.apache.drill.exec.ops.FragmentContext;
 import org.apache.drill.exec.proto.BitControl.FragmentStatus;
 import org.apache.drill.exec.proto.ExecProtos.FragmentHandle;
 import org.apache.drill.exec.proto.UserBitShared.FragmentState;
 import org.apache.drill.exec.proto.UserBitShared.MinorFragmentProfile;
-import org.apache.drill.exec.work.ErrorHelper;
 
 public abstract class AbstractStatusReporter implements StatusReporter{
   static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(AbstractStatusReporter.class);
@@ -37,17 +37,17 @@ public abstract class AbstractStatusReporter implements StatusReporter{
   }
 
   private  FragmentStatus.Builder getBuilder(FragmentState state){
-    return getBuilder(context, state, null, null);
+    return getBuilder(context, state, null);
   }
 
-  public static FragmentStatus.Builder getBuilder(FragmentContext context, FragmentState state, String message, Throwable t){
+  public static FragmentStatus.Builder getBuilder(FragmentContext context, FragmentState state, DrillUserException ex){
     FragmentStatus.Builder status = FragmentStatus.newBuilder();
     MinorFragmentProfile.Builder b = MinorFragmentProfile.newBuilder();
     context.getStats().addMetricsToStatus(b);
     b.setState(state);
-    if(t != null){
+    if(ex != null){
       boolean verbose = context.getOptions().getOption(ExecConstants.ENABLE_VERBOSE_ERRORS_KEY).bool_val;
-      b.setError(ErrorHelper.logAndConvertMessageError(context.getIdentity(), message, t, logger, verbose));
+      b.setError(ex.getOrCreatePBError(verbose));
     }
     status.setHandle(context.getHandle());
     b.setMemoryUsed(context.getAllocator().getAllocatedMemory());
@@ -105,8 +105,8 @@ public abstract class AbstractStatusReporter implements StatusReporter{
   protected abstract void statusChange(FragmentHandle handle, FragmentStatus status);
 
   @Override
-  public final void fail(FragmentHandle handle, String message, Throwable excep) {
-    FragmentStatus.Builder status = getBuilder(context, FragmentState.FAILED, message, excep);
+  public final void fail(FragmentHandle handle, String message, DrillUserException excep) {
+    FragmentStatus.Builder status = getBuilder(context, FragmentState.FAILED, excep);
     fail(handle, status);
   }
 

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/FragmentExecutor.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/FragmentExecutor.java b/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/FragmentExecutor.java
index a7e6c46..58f4256 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/FragmentExecutor.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/FragmentExecutor.java
@@ -21,6 +21,8 @@ import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.drill.common.DeferredException;
+import org.apache.drill.common.exceptions.DrillUserException;
+import org.apache.drill.common.exceptions.ErrorHelper;
 import org.apache.drill.exec.coord.ClusterCoordinator;
 import org.apache.drill.exec.ops.FragmentContext;
 import org.apache.drill.exec.physical.base.FragmentRoot;
@@ -83,9 +85,8 @@ public class FragmentExecutor implements Runnable {
     if(state.get() != FragmentState.RUNNING_VALUE) {
       return null;
     }
-    final FragmentStatus status =
-        AbstractStatusReporter.getBuilder(fragmentContext, FragmentState.RUNNING, null, null).build();
-    return status;
+
+    return AbstractStatusReporter.getBuilder(fragmentContext, FragmentState.RUNNING, null).build();
   }
 
   public void cancel() {
@@ -227,7 +228,11 @@ public class FragmentExecutor implements Runnable {
 
   private void internalFail(final Throwable excep) {
     state.set(FragmentState.FAILED_VALUE);
-    listener.fail(fragmentContext.getHandle(), "Failure while running fragment.", excep);
+
+    DrillUserException uex = ErrorHelper.wrap(excep);
+    uex.getContext().add(getContext().getIdentity());
+
+    listener.fail(fragmentContext.getHandle(), "Failure while running fragment.", uex);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/StatusReporter.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/StatusReporter.java b/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/StatusReporter.java
index 26b5d68..1699322 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/StatusReporter.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/work/fragment/StatusReporter.java
@@ -17,6 +17,7 @@
  */
 package org.apache.drill.exec.work.fragment;
 
+import org.apache.drill.common.exceptions.DrillUserException;
 import org.apache.drill.exec.proto.ExecProtos.FragmentHandle;
 import org.apache.drill.exec.proto.UserBitShared.FragmentState;
 
@@ -24,6 +25,6 @@ import org.apache.drill.exec.proto.UserBitShared.FragmentState;
  * The status handler is responsible for receiving changes in fragment status and propagating them back to the foreman.
  */
 public interface StatusReporter {
-  void fail(FragmentHandle handle, String message, Throwable excep);
+  void fail(FragmentHandle handle, String message, DrillUserException excep);
   void stateChanged(FragmentHandle handle, FragmentState newState);
 }

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/test/java/org/apache/drill/BaseTestQuery.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/test/java/org/apache/drill/BaseTestQuery.java b/exec/java-exec/src/test/java/org/apache/drill/BaseTestQuery.java
index 0c2f0e5..6df5801 100644
--- a/exec/java-exec/src/test/java/org/apache/drill/BaseTestQuery.java
+++ b/exec/java-exec/src/test/java/org/apache/drill/BaseTestQuery.java
@@ -25,9 +25,8 @@ import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import com.google.common.base.Preconditions;
-import com.google.common.io.Files;
 import org.apache.drill.common.config.DrillConfig;
-import org.apache.drill.common.exceptions.ExecutionSetupException;
+import org.apache.drill.common.exceptions.DrillUserException;
 import org.apache.drill.exec.ExecConstants;
 import org.apache.drill.exec.ExecTest;
 import org.apache.drill.exec.client.DrillClient;
@@ -37,7 +36,6 @@ import org.apache.drill.exec.memory.TopLevelAllocator;
 import org.apache.drill.exec.proto.UserBitShared.QueryId;
 import org.apache.drill.exec.proto.UserBitShared.QueryType;
 import org.apache.drill.exec.record.RecordBatchLoader;
-import org.apache.drill.exec.rpc.RpcException;
 import org.apache.drill.exec.rpc.user.ConnectionThrottle;
 import org.apache.drill.exec.rpc.user.QueryDataBatch;
 import org.apache.drill.exec.rpc.user.UserResultsListener;
@@ -45,9 +43,6 @@ import org.apache.drill.exec.server.Drillbit;
 import org.apache.drill.exec.server.DrillbitContext;
 import org.apache.drill.exec.server.RemoteServiceSet;
 import org.apache.drill.exec.store.StoragePluginRegistry;
-import org.apache.drill.exec.store.dfs.FileSystemConfig;
-import org.apache.drill.exec.store.dfs.FileSystemPlugin;
-import org.apache.drill.exec.store.dfs.WorkspaceConfig;
 import org.apache.drill.exec.util.TestUtilities;
 import org.apache.drill.exec.util.VectorUtil;
 import org.junit.AfterClass;
@@ -325,12 +320,12 @@ public class BaseTestQuery extends ExecTest {
   }
 
   private static class SilentListener implements UserResultsListener {
-    private volatile Exception exception;
+    private volatile DrillUserException exception;
     private AtomicInteger count = new AtomicInteger();
     private CountDownLatch latch = new CountDownLatch(1);
 
     @Override
-    public void submissionFailed(RpcException ex) {
+    public void submissionFailed(DrillUserException ex) {
       exception = ex;
       System.out.println("Query failed: " + ex.getMessage());
       latch.countDown();

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/test/java/org/apache/drill/SingleRowListener.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/test/java/org/apache/drill/SingleRowListener.java b/exec/java-exec/src/test/java/org/apache/drill/SingleRowListener.java
index 5703bf9..715904d 100644
--- a/exec/java-exec/src/test/java/org/apache/drill/SingleRowListener.java
+++ b/exec/java-exec/src/test/java/org/apache/drill/SingleRowListener.java
@@ -23,11 +23,11 @@ import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.apache.drill.common.exceptions.DrillUserException;
 import org.apache.drill.exec.proto.UserBitShared.QueryId;
 import org.apache.drill.exec.proto.UserBitShared.QueryData;
 import org.apache.drill.exec.proto.UserBitShared.QueryResult.QueryState;
 import org.apache.drill.exec.proto.UserBitShared.DrillPBError;
-import org.apache.drill.exec.rpc.RpcException;
 import org.apache.drill.exec.rpc.user.ConnectionThrottle;
 import org.apache.drill.exec.rpc.user.QueryDataBatch;
 import org.apache.drill.exec.rpc.user.UserResultsListener;
@@ -49,10 +49,10 @@ public abstract class SingleRowListener implements UserResultsListener {
   }
 
   @Override
-  public void submissionFailed(final RpcException ex) {
+  public void submissionFailed(final DrillUserException ex) {
     exception = ex;
     synchronized(errorList) {
-      errorList.add(ex.getRemoteError());
+      errorList.add(ex.getOrCreatePBError(false));
     }
     latch.countDown();
   }

http://git-wip-us.apache.org/repos/asf/drill/blob/99b6d0e6/exec/java-exec/src/test/java/org/apache/drill/TestBugFixes.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/test/java/org/apache/drill/TestBugFixes.java b/exec/java-exec/src/test/java/org/apache/drill/TestBugFixes.java
index 875fb25..12b1787 100644
--- a/exec/java-exec/src/test/java/org/apache/drill/TestBugFixes.java
+++ b/exec/java-exec/src/test/java/org/apache/drill/TestBugFixes.java
@@ -17,7 +17,7 @@
  */
 package org.apache.drill;
 
-import org.apache.drill.exec.rpc.RpcException;
+import org.apache.drill.common.exceptions.DrillUserException;
 import org.junit.Ignore;
 import org.junit.Test;
 
@@ -73,13 +73,13 @@ public class TestBugFixes extends BaseTestQuery {
   }
 
 
-  @Test (expected = RpcException.class)
+  @Test (expected = DrillUserException.class)
   // Should be "Failure while parsing sql. Node [rel#26:Subset#6.LOGICAL.ANY([]).[]] could not be implemented;".
   // Drill will hit CanNotPlan, until we add code fix to transform the local LHS filter in left outer join properly.
   public void testDRILL1337_LocalLeftFilterLeftOutJoin() throws Exception {
     try {
       test("select count(*) from cp.`tpch/nation.parquet` n left outer join cp.`tpch/region.parquet` r on n.n_regionkey = r.r_regionkey and n.n_nationkey > 10;");
-    } catch (RpcException e) {
+    } catch (DrillUserException e) {
       logger.info("***** Test resulted in expected failure: " + e.getMessage());
       throw e;
     }