diff --git a/src/main/java/io/github/jamsesso/jsonlogic/JsonLogic.java b/src/main/java/io/github/jamsesso/jsonlogic/JsonLogic.java
index 47add88..fa25f2f 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/JsonLogic.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/JsonLogic.java
@@ -57,7 +57,7 @@ public JsonLogic() {
   public JsonLogic addOperation(String name, Function<Object[], Object> function) {
     return addOperation(new PreEvaluatedArgumentsExpression() {
       @Override
-      public Object evaluate(List arguments, Object data) {
+      public Object evaluate(List arguments, Object data, String jsonPath) {
         return function.apply(arguments.toArray());
       }
 
@@ -84,7 +84,7 @@ public Object apply(String json, Object data) throws JsonLogicException {
       evaluator = new JsonLogicEvaluator(expressions);
     }
 
-    return evaluator.evaluate(parseCache.get(json), data);
+    return evaluator.evaluate(parseCache.get(json), data, "$");
   }
 
   public static boolean truthy(Object value) {
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/JsonLogicException.java b/src/main/java/io/github/jamsesso/jsonlogic/JsonLogicException.java
index 0c03d25..71b961f 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/JsonLogicException.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/JsonLogicException.java
@@ -1,19 +1,24 @@
 package io.github.jamsesso.jsonlogic;
 
 public class JsonLogicException extends Exception {
+
+  private String jsonPath;
+
   private JsonLogicException() {
     // The default constructor should not be called for exceptions. A reason must be provided.
   }
 
-  public JsonLogicException(String msg) {
+  public JsonLogicException(String msg, String jsonPath) {
     super(msg);
+    this.jsonPath = jsonPath;
   }
 
-  public JsonLogicException(Throwable cause) {
+  public JsonLogicException(Throwable cause, String jsonPath) {
     super(cause);
+    this.jsonPath = jsonPath;
   }
 
-  public JsonLogicException(String msg, Throwable cause) {
-    super(msg, cause);
+  public String getJsonPath() {
+    return jsonPath;
   }
 }
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicParseException.java b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicParseException.java
index ff43164..1df20ec 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicParseException.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicParseException.java
@@ -3,15 +3,11 @@
 import io.github.jamsesso.jsonlogic.JsonLogicException;
 
 public class JsonLogicParseException extends JsonLogicException {
-  public JsonLogicParseException(String msg) {
-    super(msg);
+  public JsonLogicParseException(String msg, String jsonPath) {
+    super(msg, jsonPath);
   }
 
-  public JsonLogicParseException(Throwable cause) {
-    super(cause);
-  }
-
-  public JsonLogicParseException(String msg, Throwable cause) {
-    super(msg, cause);
+  public JsonLogicParseException(Throwable cause, String jsonPath) {
+    super(cause, jsonPath);
   }
 }
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicParser.java b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicParser.java
index 21cfba7..bf442b8 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicParser.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/ast/JsonLogicParser.java
@@ -18,11 +18,14 @@ public static JsonLogicNode parse(String json) throws JsonLogicParseException {
       return parse(PARSER.parse(json));
     }
     catch (JsonSyntaxException e) {
-      throw new JsonLogicParseException(e);
+      throw new JsonLogicParseException(e, "$");
     }
   }
 
   private static JsonLogicNode parse(JsonElement root) throws JsonLogicParseException {
+    return parse(root, "$");
+  }
+  private static JsonLogicNode parse(JsonElement root, String jsonPath) throws JsonLogicParseException {
     // Handle null
     if (root.isJsonNull()) {
       return JsonLogicNull.NULL;
@@ -53,8 +56,9 @@ private static JsonLogicNode parse(JsonElement root) throws JsonLogicParseExcept
       JsonArray array = root.getAsJsonArray();
       List<JsonLogicNode> elements = new ArrayList<>(array.size());
 
+      int index = 0;
       for (JsonElement element : array) {
-        elements.add(parse(element));
+        elements.add(parse(element, String.format("%s[%d]", jsonPath, index++)));
       }
 
       return new JsonLogicArray(elements);
@@ -64,11 +68,11 @@ private static JsonLogicNode parse(JsonElement root) throws JsonLogicParseExcept
     JsonObject object = root.getAsJsonObject();
 
     if (object.keySet().size() != 1) {
-      throw new JsonLogicParseException("objects must have exactly 1 key defined, found " + object.keySet().size());
+      throw new JsonLogicParseException("objects must have exactly 1 key defined, found " + object.keySet().size(), jsonPath);
     }
 
     String key = object.keySet().stream().findAny().get();
-    JsonLogicNode argumentNode = parse(object.get(key));
+    JsonLogicNode argumentNode = parse(object.get(key), String.format("%s.%s", jsonPath, key));
     JsonLogicArray arguments;
 
     // Always coerce single-argument operations into a JsonLogicArray with a single element.
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicEvaluationException.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicEvaluationException.java
index 20394f9..2fcf35d 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicEvaluationException.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicEvaluationException.java
@@ -3,15 +3,11 @@
 import io.github.jamsesso.jsonlogic.JsonLogicException;
 
 public class JsonLogicEvaluationException extends JsonLogicException {
-  public JsonLogicEvaluationException(String msg) {
-    super(msg);
+  public JsonLogicEvaluationException(String msg, String jsonPath) {
+    super(msg, jsonPath);
   }
 
-  public JsonLogicEvaluationException(Throwable cause) {
-    super(cause);
-  }
-
-  public JsonLogicEvaluationException(String msg, Throwable cause) {
-    super(msg, cause);
+  public JsonLogicEvaluationException(Throwable cause, String jsonPath) {
+    super(cause, jsonPath);
   }
 }
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicEvaluator.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicEvaluator.java
index 804ee1e..d78892b 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicEvaluator.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicEvaluator.java
@@ -20,12 +20,12 @@ public JsonLogicEvaluator(Map<String, JsonLogicExpression> expressions) {
     this.expressions = Collections.unmodifiableMap(expressions);
   }
 
-  public Object evaluate(JsonLogicNode node, Object data) throws JsonLogicEvaluationException {
+  public Object evaluate(JsonLogicNode node, Object data, String jsonPath) throws JsonLogicEvaluationException {
     switch (node.getType()) {
       case PRIMITIVE: return evaluate((JsonLogicPrimitive) node);
-      case VARIABLE: return evaluate((JsonLogicVariable) node, data);
-      case ARRAY: return evaluate((JsonLogicArray) node, data);
-      default: return evaluate((JsonLogicOperation) node, data);
+      case VARIABLE: return evaluate((JsonLogicVariable) node, data, jsonPath + ".var");
+      case ARRAY: return evaluate((JsonLogicArray) node, data, jsonPath);
+      default: return evaluate((JsonLogicOperation) node, data, jsonPath);
     }
   }
 
@@ -38,19 +38,20 @@ public Object evaluate(JsonLogicPrimitive<?> primitive) {
     }
   }
 
-  public Object evaluate(JsonLogicVariable variable, Object data) throws JsonLogicEvaluationException {
-    Object defaultValue = evaluate(variable.getDefaultValue(), null);
+  public Object evaluate(JsonLogicVariable variable, Object data, String jsonPath)
+      throws JsonLogicEvaluationException {
+    Object defaultValue = evaluate(variable.getDefaultValue(), null, jsonPath + "[1]");
 
     if (data == null) {
       return defaultValue;
     }
 
-    Object key = evaluate(variable.getKey(), data);
+    Object key = evaluate(variable.getKey(), data, jsonPath + "[0]");
 
     if (key == null) {
       return Optional.of(data)
         .map(JsonLogicEvaluator::transform)
-        .orElse(evaluate(variable.getDefaultValue(), null));
+        .orElse(evaluate(variable.getDefaultValue(), null, jsonPath + "[1]"));
     }
 
     if (key instanceof Number) {
@@ -78,10 +79,10 @@ public Object evaluate(JsonLogicVariable variable, Object data) throws JsonLogic
       String[] keys = name.split("\\.");
       Object result = data;
 
-      for(String partial : keys) {
-        result = evaluatePartialVariable(partial, result);
+      for (String partial : keys) {
+        result = evaluatePartialVariable(partial, result, jsonPath + "[0]");
 
-        if(result == null) {
+        if (result == null) {
           return defaultValue;
         }
       }
@@ -89,10 +90,10 @@ public Object evaluate(JsonLogicVariable variable, Object data) throws JsonLogic
       return result;
     }
 
-    throw new JsonLogicEvaluationException("var first argument must be null, number, or string");
+    throw new JsonLogicEvaluationException("var first argument must be null, number, or string", jsonPath + "[0]");
   }
 
-  private Object evaluatePartialVariable(String key, Object data) throws JsonLogicEvaluationException {
+  private Object evaluatePartialVariable(String key, Object data, String jsonPath) throws JsonLogicEvaluationException {
     if (ArrayLike.isEligible(data)) {
       ArrayLike list = new ArrayLike(data);
       int index;
@@ -101,7 +102,7 @@ private Object evaluatePartialVariable(String key, Object data) throws JsonLogic
         index = Integer.parseInt(key);
       }
       catch (NumberFormatException e) {
-        throw new JsonLogicEvaluationException(e);
+        throw new JsonLogicEvaluationException(e, jsonPath);
       }
 
       if (index < 0 || index >= list.size()) {
@@ -118,24 +119,25 @@ private Object evaluatePartialVariable(String key, Object data) throws JsonLogic
     return null;
   }
 
-  public List<Object> evaluate(JsonLogicArray array, Object data) throws JsonLogicEvaluationException {
+  public List<Object> evaluate(JsonLogicArray array, Object data, String jsonPath) throws JsonLogicEvaluationException {
     List<Object> values = new ArrayList<>(array.size());
 
+    int index = 0;
     for(JsonLogicNode element : array) {
-      values.add(evaluate(element, data));
+      values.add(evaluate(element, data, String.format("%s[%d]", jsonPath, index++)));
     }
 
     return values;
   }
 
-  public Object evaluate(JsonLogicOperation operation, Object data) throws JsonLogicEvaluationException {
+  public Object evaluate(JsonLogicOperation operation, Object data, String jsonPath) throws JsonLogicEvaluationException {
     JsonLogicExpression handler = expressions.get(operation.getOperator());
 
     if (handler == null) {
-      throw new JsonLogicEvaluationException("Undefined operation '" + operation.getOperator() + "'");
+      throw new JsonLogicEvaluationException("Undefined operation '" + operation.getOperator() + "'", jsonPath);
     }
 
-    return handler.evaluate(this, operation.getArguments(), data);
+    return handler.evaluate(this, operation.getArguments(), data, String.format("%s.%s", jsonPath, operation.getOperator()));
   }
 
   public static Object transform(Object value) {
@@ -145,4 +147,4 @@ public static Object transform(Object value) {
 
     return value;
   }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicExpression.java
index 7c267bb..0f1381b 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/JsonLogicExpression.java
@@ -5,6 +5,6 @@
 public interface JsonLogicExpression {
   String key();
 
-  Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data)
+  Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath)
     throws JsonLogicEvaluationException;
 }
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/AllExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/AllExpression.java
index 711387a..2e9350f 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/AllExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/AllExpression.java
@@ -20,20 +20,20 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data)
+  public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath)
     throws JsonLogicEvaluationException {
     if (arguments.size() != 2) {
-      throw new JsonLogicEvaluationException("all expects exactly 2 arguments");
+      throw new JsonLogicEvaluationException("all expects exactly 2 arguments", jsonPath);
     }
 
-    Object maybeArray = evaluator.evaluate(arguments.get(0), data);
+    Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]");
 
     if (maybeArray == null) {
       return false;
     }
 
     if (!ArrayLike.isEligible(maybeArray)) {
-      throw new JsonLogicEvaluationException("first argument to all must be a valid array");
+      throw new JsonLogicEvaluationException("first argument to all must be a valid array", jsonPath);
     }
 
     ArrayLike array = new ArrayLike(maybeArray);
@@ -42,8 +42,9 @@ public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, O
       return false;
     }
 
+    int index = 1;
     for (Object item : array) {
-      if(!JsonLogic.truthy(evaluator.evaluate(arguments.get(1), item))) {
+      if(!JsonLogic.truthy(evaluator.evaluate(arguments.get(1), item,  String.format("%s[%d]", jsonPath, index)))) {
         return false;
       }
     }
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ArrayHasExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ArrayHasExpression.java
index 44d3bb5..7d9bb14 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ArrayHasExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ArrayHasExpression.java
@@ -23,13 +23,13 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data)
+  public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath)
     throws JsonLogicEvaluationException {
     if (arguments.size() != 2) {
-      throw new JsonLogicEvaluationException("some expects exactly 2 arguments");
+      throw new JsonLogicEvaluationException(key() + " expects exactly 2 arguments", jsonPath);
     }
 
-    Object maybeArray = evaluator.evaluate(arguments.get(0), data);
+    Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]");
 
     // Array objects can have null values according to http://jsonlogic.com/
     if (maybeArray == null) {
@@ -41,15 +41,15 @@ public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, O
     }
 
     if (!ArrayLike.isEligible(maybeArray)) {
-      throw new JsonLogicEvaluationException("first argument to some must be a valid array");
+      throw new JsonLogicEvaluationException("first argument to " + key() + " must be a valid array", jsonPath + "[0]");
     }
 
     for (Object item : new ArrayLike(maybeArray)) {
-      if(JsonLogic.truthy(evaluator.evaluate(arguments.get(1), item))) {
+      if(JsonLogic.truthy(evaluator.evaluate(arguments.get(1), item, jsonPath + "[1]"))) {
         return isSome;
       }
     }
 
     return !isSome;
   }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ConcatenateExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ConcatenateExpression.java
index 81dd180..1ef7651 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ConcatenateExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ConcatenateExpression.java
@@ -18,7 +18,7 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException {
+  public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException {
     return arguments.stream()
       .map(obj -> {
         if (obj instanceof Double && obj.toString().endsWith(".0")) {
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/EqualityExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/EqualityExpression.java
index efde9ef..0262ba1 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/EqualityExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/EqualityExpression.java
@@ -18,9 +18,9 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException {
+  public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException {
     if (arguments.size() != 2) {
-      throw new JsonLogicEvaluationException("equality expressions expect exactly 2 arguments");
+      throw new JsonLogicEvaluationException("equality expressions expect exactly 2 arguments", jsonPath);
     }
 
     Object left = arguments.get(0);
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/FilterExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/FilterExpression.java
index 520c06e..79364e9 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/FilterExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/FilterExpression.java
@@ -23,22 +23,22 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data)
+  public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath)
     throws JsonLogicEvaluationException {
     if (arguments.size() != 2) {
-      throw new JsonLogicEvaluationException("filter expects exactly 2 arguments");
+      throw new JsonLogicEvaluationException("filter expects exactly 2 arguments", jsonPath);
     }
 
-    Object maybeArray = evaluator.evaluate(arguments.get(0), data);
+    Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]");
 
     if (!ArrayLike.isEligible(maybeArray)) {
-      throw new JsonLogicEvaluationException("first argument to filter must be a valid array");
+      throw new JsonLogicEvaluationException("first argument to filter must be a valid array", jsonPath + "[0]");
     }
 
     List<Object> result = new ArrayList<>();
 
     for (Object item : new ArrayLike(maybeArray)) {
-      if(JsonLogic.truthy(evaluator.evaluate(arguments.get(1), item))) {
+      if(JsonLogic.truthy(evaluator.evaluate(arguments.get(1), item, jsonPath + "[1]"))) {
         result.add(item);
       }
     }
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/IfExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/IfExpression.java
index 165c6b7..230a636 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/IfExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/IfExpression.java
@@ -23,7 +23,8 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data)
+  public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data,
+      String jsonPath)
     throws JsonLogicEvaluationException {
     if (arguments.size() < 1) {
       return null;
@@ -31,13 +32,13 @@ public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, O
 
     // If there is only a single argument, simply evaluate & return that argument.
     if (arguments.size() == 1) {
-      return evaluator.evaluate(arguments.get(0), data);
+      return evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]");
     }
 
     // If there is 2 arguments, only evaluate the second argument if the first argument is truthy.
     if (arguments.size() == 2) {
-      return JsonLogic.truthy(evaluator.evaluate(arguments.get(0), data))
-        ? evaluator.evaluate(arguments.get(1), data)
+      return JsonLogic.truthy(evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]"))
+        ? evaluator.evaluate(arguments.get(1), data, jsonPath + "[1]")
         : null;
     }
 
@@ -45,8 +46,8 @@ public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, O
       JsonLogicNode condition = arguments.get(i);
       JsonLogicNode resultIfTrue = arguments.get(i + 1);
 
-      if (JsonLogic.truthy(evaluator.evaluate(condition, data))) {
-        return evaluator.evaluate(resultIfTrue, data);
+      if (JsonLogic.truthy(evaluator.evaluate(condition, data, String.format("%s[%d]", jsonPath, i)))) {
+        return evaluator.evaluate(resultIfTrue, data, String.format("%s[%d]", jsonPath, i + 1));
       }
     }
 
@@ -54,6 +55,6 @@ public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, O
       return null;
     }
 
-    return evaluator.evaluate(arguments.get(arguments.size() - 1), data);
+    return evaluator.evaluate(arguments.get(arguments.size() - 1), data, String.format("%s[%d]", jsonPath, arguments.size() - 1));
   }
 }
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/InExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/InExpression.java
index 848adf0..e5f6d0b 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/InExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/InExpression.java
@@ -18,7 +18,7 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException {
+  public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException {
     if (arguments.size() < 2) {
       return false;
     }
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/InequalityExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/InequalityExpression.java
index a0ae49a..747afb0 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/InequalityExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/InequalityExpression.java
@@ -20,9 +20,9 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data)
+  public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath)
     throws JsonLogicEvaluationException {
-    boolean result = (boolean) delegate.evaluate(evaluator, arguments, data);
+    boolean result = (boolean) delegate.evaluate(evaluator, arguments, data, jsonPath);
 
     return !result;
   }
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/LogExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/LogExpression.java
index e82c261..43332c5 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/LogExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/LogExpression.java
@@ -20,9 +20,9 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException {
+  public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException {
     if (arguments.isEmpty()) {
-      throw new JsonLogicEvaluationException("log operator requires exactly 1 argument");
+      throw new JsonLogicEvaluationException("log operator requires exactly 1 argument", jsonPath);
     }
 
     Object value = arguments.get(0);
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/LogicExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/LogicExpression.java
index 0397b14..02a8f28 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/LogicExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/LogicExpression.java
@@ -23,16 +23,17 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data)
+  public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath)
     throws JsonLogicEvaluationException {
     if (arguments.size() < 1) {
-      throw new JsonLogicEvaluationException("and operator expects at least 1 argument");
+      throw new JsonLogicEvaluationException(key() + " operator expects at least 1 argument", jsonPath);
     }
 
     Object result = null;
 
+    int index = 0;
     for (JsonLogicNode element : arguments) {
-      result = evaluator.evaluate(element, data);
+      result = evaluator.evaluate(element, data, String.format("%s[%d]", jsonPath, index));
 
       if ((isAnd && !JsonLogic.truthy(result)) || (!isAnd && JsonLogic.truthy(result))) {
         return result;
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MapExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MapExpression.java
index f046ede..9c3a863 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MapExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MapExpression.java
@@ -23,13 +23,13 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data)
+  public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath)
     throws JsonLogicEvaluationException {
     if (arguments.size() != 2) {
-      throw new JsonLogicEvaluationException("map expects exactly 2 arguments");
+      throw new JsonLogicEvaluationException("map expects exactly 2 arguments", jsonPath);
     }
 
-    Object maybeArray = evaluator.evaluate(arguments.get(0), data);
+    Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]");
 
     if (!ArrayLike.isEligible(maybeArray)) {
       return Collections.emptyList();
@@ -38,7 +38,7 @@ public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, O
     List<Object> result = new ArrayList<>();
 
     for (Object item : new ArrayLike(maybeArray)) {
-      result.add(evaluator.evaluate(arguments.get(1), item));
+      result.add(evaluator.evaluate(arguments.get(1), item, jsonPath + "[1]"));
     }
 
     return result;
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MathExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MathExpression.java
index a077a54..4703715 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MathExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MathExpression.java
@@ -1,6 +1,7 @@
 package io.github.jamsesso.jsonlogic.evaluator.expressions;
 
 import io.github.jamsesso.jsonlogic.evaluator.JsonLogicEvaluationException;
+import io.github.jamsesso.jsonlogic.utils.ArrayLike;
 
 import java.util.List;
 import java.util.function.BiFunction;
@@ -34,36 +35,22 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException {
+  public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException {
     if (arguments.isEmpty()) {
       return null;
     }
 
-    if (arguments.size() == 1) {
-      if (key.equals("+") && arguments.get(0) instanceof String) {
-        try {
-          return Double.parseDouble((String) arguments.get(0));
-        }
-        catch (NumberFormatException e) {
-          throw new JsonLogicEvaluationException(e);
-        }
-      }
-
-      if (key.equals("-") && arguments.get(0) instanceof Number) {
-        return -1 * ((Number) arguments.get(0)).doubleValue();
-      }
-
-      if (key.equals("/")) {
-        return null;
-      }
-    }
-
     // Collect all of the arguments
     double[] values = new double[arguments.size()];
 
     for (int i = 0; i < arguments.size(); i++) {
       Object value = arguments.get(i);
 
+      if (key.equals("*") || key.equals("+")) {
+        while (ArrayLike.isEligible(value)) {
+          value = new ArrayLike(value).get(0);
+        }
+      }
       if (value instanceof String) {
         try {
           values[i] = Double.parseDouble((String) value);
@@ -80,6 +67,16 @@ else if (!(value instanceof Number)) {
       }
     }
 
+    if (values.length == 1) {
+      if (key.equals("-")) {
+        return -values[0];
+      }
+
+      if (key.equals("/")) {
+        return null;
+      }
+    }
+
     // Reduce the values into a single result
     double accumulator = values[0];
 
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MergeExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MergeExpression.java
index ba34d9b..a07d005 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MergeExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MergeExpression.java
@@ -22,11 +22,10 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException {
+  public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException {
     return ((List<Object>) arguments).stream()
       .map(obj -> ArrayLike.isEligible(obj) ? new ArrayLike(obj) : Collections.singleton(obj))
-      .map(Collection::stream)
-      .flatMap(Function.identity())
+      .flatMap(Collection::stream)
       .collect(Collectors.toList());
   }
 }
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MissingExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MissingExpression.java
index 2e073bd..a03a616 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MissingExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/MissingExpression.java
@@ -22,10 +22,10 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException {
-    if (isSome && (!ArrayLike.isEligible(arguments.get(1)) || !(arguments.get(0) instanceof Double))) {
+  public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException {
+    if (isSome && (arguments.size() < 2 || !ArrayLike.isEligible(arguments.get(1)) || !(arguments.get(0) instanceof Double))) {
       throw new JsonLogicEvaluationException("missing_some expects first argument to be an integer and the second " +
-              "argument to be an array");
+              "argument to be an array", jsonPath);
     }
 
     if (!MapLike.isEligible(data)) {
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/NotExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/NotExpression.java
index 2fa0e72..e653129 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/NotExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/NotExpression.java
@@ -20,7 +20,7 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(List arguments, Object data) {
+  public Object evaluate(List arguments, Object data, String jsonPath) {
     boolean result;
 
     if (arguments.isEmpty()) {
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/NumericComparisonExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/NumericComparisonExpression.java
index 897817d..98c98a4 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/NumericComparisonExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/NumericComparisonExpression.java
@@ -22,12 +22,12 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException {
+  public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException {
     // Convert the arguments to doubles
     int n = Math.min(arguments.size(), 3);
 
     if (n < 2) {
-      throw new JsonLogicEvaluationException("'" + key + "' requires at least 2 arguments");
+      throw new JsonLogicEvaluationException("'" + key + "' requires at least 2 arguments", jsonPath);
     }
 
     double[] values = new double[n];
@@ -51,8 +51,8 @@ else if (!(value instanceof Number)) {
       }
     }
 
-    // Handle between comparisons (supported for < and <=)
-    if (arguments.size() == 3) {
+    // Handle between comparisons
+    if (arguments.size() >= 3) {
       switch (key) {
         case "<":
           return values[0] < values[1] && values[1] < values[2];
@@ -60,8 +60,14 @@ else if (!(value instanceof Number)) {
         case "<=":
           return values[0] <= values[1] && values[1] <= values[2];
 
+        case ">":
+          return values[0] > values[1] && values[1] > values[2];
+
+        case ">=":
+          return values[0] >= values[1] && values[1] >= values[2];
+
         default:
-          throw new JsonLogicEvaluationException("'" + key + "' does not support between comparisons");
+          throw new JsonLogicEvaluationException("'" + key + "' does not support between comparisons", jsonPath);
       }
     }
 
@@ -80,7 +86,7 @@ else if (!(value instanceof Number)) {
         return values[0] >= values[1];
 
       default:
-        throw new JsonLogicEvaluationException("'" + key + "' is not a comparison expression");
+        throw new JsonLogicEvaluationException("'" + key + "' is not a comparison expression", jsonPath);
     }
   }
 }
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/PreEvaluatedArgumentsExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/PreEvaluatedArgumentsExpression.java
index 4c53896..26adfe4 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/PreEvaluatedArgumentsExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/PreEvaluatedArgumentsExpression.java
@@ -9,17 +9,17 @@
 import java.util.List;
 
 public interface PreEvaluatedArgumentsExpression extends JsonLogicExpression {
-  Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException;
+  Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException;
 
   @Override
-  default Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data)
+  default Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath)
     throws JsonLogicEvaluationException {
-    List<Object> values = evaluator.evaluate(arguments, data);
+    List<Object> values = evaluator.evaluate(arguments, data, jsonPath);
 
     if (values.size() == 1 && ArrayLike.isEligible(values.get(0))) {
       values = new ArrayLike(values.get(0));
     }
 
-    return evaluate(values, data);
+    return evaluate(values, data, jsonPath);
   }
 }
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ReduceExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ReduceExpression.java
index 7864cc5..35bb882 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ReduceExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/ReduceExpression.java
@@ -22,14 +22,14 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data)
+  public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath)
     throws JsonLogicEvaluationException {
     if (arguments.size() != 3) {
-      throw new JsonLogicEvaluationException("reduce expects exactly 3 arguments");
+      throw new JsonLogicEvaluationException("reduce expects exactly 3 arguments", jsonPath);
     }
 
-    Object maybeArray = evaluator.evaluate(arguments.get(0), data);
-    Object accumulator = evaluator.evaluate(arguments.get(2), data);
+    Object maybeArray = evaluator.evaluate(arguments.get(0), data, jsonPath + "[0]");
+    Object accumulator = evaluator.evaluate(arguments.get(2), data, jsonPath + "[2]");
 
     if (!ArrayLike.isEligible(maybeArray)) {
       return accumulator;
@@ -40,7 +40,7 @@ public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, O
 
     for (Object item : new ArrayLike(maybeArray)) {
       context.put("current", item);
-      context.put("accumulator", evaluator.evaluate(arguments.get(1), context));
+      context.put("accumulator", evaluator.evaluate(arguments.get(1), context, jsonPath + "[1]"));
     }
 
     return context.get("accumulator");
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/StrictEqualityExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/StrictEqualityExpression.java
index fcf2325..8cbfc04 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/StrictEqualityExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/StrictEqualityExpression.java
@@ -17,9 +17,9 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException {
+  public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException {
     if (arguments.size() != 2) {
-      throw new JsonLogicEvaluationException("equality expressions expect exactly 2 arguments");
+      throw new JsonLogicEvaluationException("equality expressions expect exactly 2 arguments", jsonPath);
     }
 
     Object left = arguments.get(0);
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/StrictInequalityExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/StrictInequalityExpression.java
index 41d71ee..68e257c 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/StrictInequalityExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/StrictInequalityExpression.java
@@ -21,9 +21,9 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data)
+  public Object evaluate(JsonLogicEvaluator evaluator, JsonLogicArray arguments, Object data, String jsonPath)
     throws JsonLogicEvaluationException {
-    boolean result = (boolean) delegate.evaluate(evaluator, arguments, data);
+    boolean result = (boolean) delegate.evaluate(evaluator, arguments, data, jsonPath);
 
     return !result;
   }
diff --git a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/SubstringExpression.java b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/SubstringExpression.java
index f9f844f..6fc8b7b 100644
--- a/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/SubstringExpression.java
+++ b/src/main/java/io/github/jamsesso/jsonlogic/evaluator/expressions/SubstringExpression.java
@@ -17,13 +17,13 @@ public String key() {
   }
 
   @Override
-  public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationException {
+  public Object evaluate(List arguments, Object data, String jsonPath) throws JsonLogicEvaluationException {
     if (arguments.size() < 2 || arguments.size() > 3) {
-      throw new JsonLogicEvaluationException("substr expects 2 or 3 arguments");
+      throw new JsonLogicEvaluationException("substr expects 2 or 3 arguments", jsonPath);
     }
 
     if (!(arguments.get(1) instanceof Double)) {
-      throw new JsonLogicEvaluationException("first argument to substr must be a number");
+      throw new JsonLogicEvaluationException("second argument to substr must be a number", jsonPath + "[1]");
     }
 
     String value = arguments.get(0).toString();
@@ -44,7 +44,7 @@ public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationEx
     }
     else {
       if (!(arguments.get(2) instanceof Double)) {
-        throw new JsonLogicEvaluationException("second argument to substr must be an integer");
+        throw new JsonLogicEvaluationException("third argument to substr must be an integer", jsonPath + "[2]");
       }
 
       startIndex = ((Double) arguments.get(1)).intValue();
diff --git a/src/test/java/io/github/jamsesso/jsonlogic/MathExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/MathExpressionTests.java
index 8d6ea8d..b7a356b 100644
--- a/src/test/java/io/github/jamsesso/jsonlogic/MathExpressionTests.java
+++ b/src/test/java/io/github/jamsesso/jsonlogic/MathExpressionTests.java
@@ -3,6 +3,7 @@
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 
 public class MathExpressionTests {
   private static final JsonLogic jsonLogic = new JsonLogic();
@@ -31,6 +32,21 @@ public void testSingleAdd() throws JsonLogicException {
     assertEquals(3.14, result);
   }
 
+  @Test
+  public void testAddWithArray() throws JsonLogicException {
+    String json = "{\"+\":[2,[[3,4],5]]}";
+    Object result = jsonLogic.apply(json, null);
+
+    assertEquals(5.0, result);  // This matches reference impl at jsonlogic.com
+  }
+
+  @Test
+  public void testStringAdd() throws JsonLogicException {
+    assertNull(jsonLogic.apply("{\"+\" : \"foo\"}", null));
+    assertNull(jsonLogic.apply("{\"+\" : [\"foo\"]}", null));
+    assertNull(jsonLogic.apply("{\"+\" : [1, \"foo\"]}", null));
+  }
+
   @Test
   public void testSubtract() throws JsonLogicException {
     String json = "{\"-\":[4,2]}";
@@ -47,6 +63,14 @@ public void testSingleSubtract() throws JsonLogicException {
     assertEquals(-2.0, result);
   }
 
+  @Test
+  public void testSingleSubtractString() throws JsonLogicException {
+    String json = "{\"-\": \"2\" }";
+    Object result = jsonLogic.apply(json, null);
+
+    assertEquals(-2.0, result);
+  }
+
   @Test
   public void testMultiply() throws JsonLogicException {
     String json = "{\"*\":[4,2]}";
@@ -63,6 +87,14 @@ public void testMultiMultiply() throws JsonLogicException {
     assertEquals(32.0, result);
   }
 
+  @Test
+  public void testMultiplyWithArray() throws JsonLogicException {
+    String json = "{\"*\":[2,[[3, 4], 5]]}";
+    Object result = jsonLogic.apply(json, null);
+
+    assertEquals(6.0, result);  // This matches reference impl at jsonlogic.com
+  }
+
   @Test
   public void testDivide() throws JsonLogicException {
     String json = "{\"/\":[4,2]}";
diff --git a/src/test/java/io/github/jamsesso/jsonlogic/NumericComparisonExpressionTests.java b/src/test/java/io/github/jamsesso/jsonlogic/NumericComparisonExpressionTests.java
index f1cbf0a..d4633b1 100644
--- a/src/test/java/io/github/jamsesso/jsonlogic/NumericComparisonExpressionTests.java
+++ b/src/test/java/io/github/jamsesso/jsonlogic/NumericComparisonExpressionTests.java
@@ -54,4 +54,26 @@ public void testBetweenInclusive() throws JsonLogicException {
 
     assertEquals(true, result);
   }
+
+  @Test
+  public void testGtBetweenExclusive() throws JsonLogicException {
+    String json = "{\">\" : [3, 2, 1]}";
+    Object result = jsonLogic.apply(json, null);
+
+    assertEquals(true, result);
+  }
+
+  @Test
+  public void testGtBetweenInclusive() throws JsonLogicException {
+    String json = "{\">=\" : [3, 1, 1]}";
+    Object result = jsonLogic.apply(json, null);
+
+    assertEquals(true, result);
+  }
+
+  @Test
+  public void testEdgeCases() throws JsonLogicException {
+    assertEquals(true, jsonLogic.apply("{\">=\" : [3, 1, 1, 1]}", null));
+    assertEquals(false, jsonLogic.apply("{\">=\" : [3, 1, 3, 1]}", null));
+  }
 }
diff --git a/src/test/java/io/github/jamsesso/jsonlogic/ParseErrorTests.java b/src/test/java/io/github/jamsesso/jsonlogic/ParseErrorTests.java
new file mode 100644
index 0000000..47882d2
--- /dev/null
+++ b/src/test/java/io/github/jamsesso/jsonlogic/ParseErrorTests.java
@@ -0,0 +1,80 @@
+package io.github.jamsesso.jsonlogic;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class ParseErrorTests {
+  private static final JsonLogic jsonLogic = new JsonLogic();
+  private static final Map<String, Object> empty = new HashMap<>();
+  private static final Map<String, Object> arrayData = Collections.singletonMap("key",
+      Stream.of(1, 2).collect(Collectors.toList()));
+
+  private void testPath(String expression, String jsonPath, String msg) {
+    testPath(expression, jsonPath, msg, empty);
+  }
+  private void testPath(String expression, String jsonPath, String msg, Map<String, Object> data) {
+    try {
+      jsonLogic.apply(expression, data);
+      fail("Expected an exception at " + jsonPath);
+    } catch (JsonLogicException e) {
+      assertEquals(e.getMessage(), jsonPath, e.getJsonPath());
+      assertEquals(msg, e.getMessage());
+    }
+  }
+
+  @Test
+  public void testJsonPath() {
+    testPath("{}", "$", "objects must have exactly 1 key defined, found 0");
+    testPath("{\"all\":[1]}","$.all","all expects exactly 2 arguments");
+    testPath("{\"all\":[{\"some\":[]}, 1]}","$.all[0].some","some expects exactly 2 arguments");
+    testPath("{\"all\":[[1], {\"none\":[]}]}","$.all[1].none","none expects exactly 2 arguments");
+    testPath("{\"some\":[0, 1]}","$.some[0]","first argument to some must be a valid array");
+    testPath("{\"none\":[1, 2]}","$.none[0]","first argument to none must be a valid array");
+    testPath("{\"cat\":[\"foo\", {}]}","$.cat[1]","objects must have exactly 1 key defined, found 0");
+    testPath("{\"==\":[0]}","$.==","equality expressions expect exactly 2 arguments");
+    testPath("{\"filter\":[0]}","$.filter","filter expects exactly 2 arguments");
+    testPath("{\"filter\":[1, 2]}","$.filter[0]","first argument to filter must be a valid array");
+    testPath("{\"filter\":[\"foo\", {}]}","$.filter[1]","objects must have exactly 1 key defined, found 0");
+    testPath("{\"if\":[{}]}","$.if[0]","objects must have exactly 1 key defined, found 0");
+    testPath("{\"if\":[true,{}]}","$.if[1]","objects must have exactly 1 key defined, found 0");
+    testPath("{\"if\":[false,1,{\"filter\":[1]}]}","$.if[2].filter","filter expects exactly 2 arguments");
+    testPath("{\"if\":[false,1,true,{\"filter\":[1]}]}","$.if[3].filter","filter expects exactly 2 arguments");
+    testPath("{\"!=\":[0]}","$.!=","equality expressions expect exactly 2 arguments");
+    testPath("{\"log\":[]}","$.log","log operator requires exactly 1 argument");
+    testPath("{\"and\":[]}","$.and","and operator expects at least 1 argument");
+    testPath("{\"or\":[]}","$.or","or operator expects at least 1 argument");
+    testPath("{\"map\":[1]}","$.map","map expects exactly 2 arguments");
+    testPath("{\"+\":[1, {\"-\": [2, {\"*\": [3, {\"/\": [4, {\"log\":[]}]}]}]}]}","$.+[1].-[1].*[1]./[1].log","log operator requires exactly 1 argument");
+    testPath("{\"%\":[1, {\"min\": [2, {\"max\": [3, {\"log\":[]}]}]}]}","$.%[1].min[1].max[1].log","log operator requires exactly 1 argument");
+    testPath("{\"merge\":[1, 2, {\"log\":[]}]}","$.merge[2].log","log operator requires exactly 1 argument");
+    testPath("{\"missing_some\":[1]}","$.missing_some","missing_some expects first argument to be an integer and the second argument to be an array");
+    testPath("{\"missing_some\":[1, 2]}","$.missing_some","missing_some expects first argument to be an integer and the second argument to be an array");
+    testPath("{\"missing\":[1, {\"log\":[]}]}","$.missing[1].log","log operator requires exactly 1 argument");
+    testPath("{\"!\":[1, {\"log\":[]}]}","$.![1].log","log operator requires exactly 1 argument");
+    testPath("{\"!!\":[{\"log\":[]}]}","$.!![0].log","log operator requires exactly 1 argument");
+    testPath("{\"<\":[1]}","$.<","'<' requires at least 2 arguments");
+    testPath("{\">\":[1]}","$.>","'>' requires at least 2 arguments");
+    testPath("{\"<=\":[1]}","$.<=","'<=' requires at least 2 arguments");
+    testPath("{\">=\":[1]}","$.>=","'>=' requires at least 2 arguments");
+    testPath("{\">\":[1, {\"log\":[]}]}","$.>[1].log","log operator requires exactly 1 argument");
+    testPath("{\">\":[0, 1, 2, \"three\", 4, 5, {\"log\":[]}]}","$.>[6].log","log operator requires exactly 1 argument");
+    testPath("{\"reduce\":[1]}","$.reduce","reduce expects exactly 3 arguments");
+    testPath("{\"reduce\":[{\"log\":[]}, 2, 3]}","$.reduce[0].log","log operator requires exactly 1 argument");
+    testPath("{\"reduce\":[[1], {\"log\":[]}, 3]}","$.reduce[1].log","log operator requires exactly 1 argument");
+    testPath("{\"reduce\":[1, 2, {\"log\":[]}]}","$.reduce[2].log","log operator requires exactly 1 argument");
+    testPath("{\"===\":[1]}","$.===","equality expressions expect exactly 2 arguments");
+    testPath("{\"!==\":[1]}","$.!==","equality expressions expect exactly 2 arguments");
+    testPath("{\"substr\":[\"jsonlogic\"]}","$.substr","substr expects 2 or 3 arguments");
+    testPath("{\"substr\":[\"jsonlogic\", \"one\"]}","$.substr[1]","second argument to substr must be a number");
+    testPath("{\"substr\":[\"jsonlogic\", 1, \"two\"]}","$.substr[2]","third argument to substr must be an integer");
+    testPath("{\"var\":[[1, 2]]}","$.var[0]","var first argument must be null, number, or string");
+    testPath("{\"var\":\"key.foo\"}","$.var[0]","java.lang.NumberFormatException: For input string: \"foo\"", arrayData);
+  }
+}