This is an automated email from the ASF dual-hosted git repository.

Cole-Greer pushed a commit to branch 3.7-dev
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


The following commit(s) were added to refs/heads/3.7-dev by this push:
     new 7e1820c51b TINKERPOP-3270 `where(P)` throws a descriptive error for 
non-String scope keys (#3559)
7e1820c51b is described below

commit 7e1820c51b4dcf5748662db9f9744ce36a664595
Author: Guian Gumpac <[email protected]>
AuthorDate: Thu Jul 23 17:23:40 2026 -0700

    TINKERPOP-3270 `where(P)` throws a descriptive error for non-String scope 
keys (#3559)
    
    Assisted-by: Kiro: Claude Opus 4.8
---
 CHANGELOG.asciidoc                                 |  2 +-
 .../traversal/step/filter/WherePredicateStep.java  | 10 ++++-
 .../process/traversal/step/filter/WhereTest.java   | 45 ++++++++++++++++++++++
 3 files changed, 54 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 605013b87e..8abe3b199a 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,7 @@ 
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 === TinkerPop 3.7.7 (Release Date: NOT OFFICIALLY RELEASED YET)
 
 * Fixed `subgraph()` to throw a descriptive error identifying the required 
`Edge` input instead of an internal `ClassCastException` when the traversal 
produces a non-edge value.
+* Fixed `where(P)` to throw a descriptive error identifying the required 
String scope key (and suggesting `is(P)` for value comparisons) instead of an 
internal `ClassCastException` when given a non-String predicate value.
 * Fixed `PeerPressure.property_name` in `gremlin-python` incorrectly mapping 
to the `pageRank` property name token.
 * Added `NextN(n)` to `Traversal` in `gremlin-go` for batched result 
iteration, providing API parity with `next(n)` in the Java, Python, and .NET 
GLVs.
 * Added `next(n)` to `Traversal` in `gremlin-javascript` for batched result 
iteration, providing API parity with `next(n)` in the Java, Python, and .NET 
GLVs.
@@ -36,7 +37,6 @@ 
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 * Removed the Mono dependency from the `gremlin-dotnet` build/release process, 
using `dotnet pack`/`dotnet nuget push` instead of `mono nuget.exe`.
 * Expanded `gremlin-python` CI matrix to test against Python 3.9, 3.10, 3.11, 
3.12, and 3.13.
 * Add Node 26 support for `gremlin-javascript` and `gremlint`.
-* Corrected numerous inaccuracies in the reference documentation, including 
wrong default values (connection pool sizes, buffer sizes, ports, timeouts), 
stale serializer class names, removed options documented as available, and 
broken code examples across the JVM, Python, `.NET`, Go, and JavaScript drivers.
 * Fixed a panic in `gremlin-go` `PartitionStrategy` when `ReadPartitions` was 
left unset.
 * Fixed `gremlin-python` `ProductiveByStrategy` to pass through the 
`productiveKeys` argument, which was previously accepted but never serialized 
to the server.
 * Deprecated `ProductiveByStrategy` which was introduced as a temporary way to 
mimic pre-3.5.0 null processing behavior.
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java
index 77c3f4abc9..55fd568ba6 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WherePredicateStep.java
@@ -101,8 +101,14 @@ public final class WherePredicateStep<S> extends 
FilterStep<S> implements Scopin
     }
 
     public String getSelectKey(final P<Object> predicate) {
-        return (String) (predicate.getValue() instanceof Collection ? 
((Collection) predicate.getValue()).iterator().next()
-                : predicate.getValue()); // hack for within("x"))
+        final Object selectKey = predicate.getValue() instanceof Collection
+                ? ((Collection) predicate.getValue()).iterator().next()
+                : predicate.getValue(); // hack for within("x")
+        if (!(selectKey instanceof String))
+            throw new IllegalArgumentException(String.format(
+                    "where(P) requires a String scope key but encountered %s; 
use is(P) to compare values",
+                    null == selectKey ? "null" : 
selectKey.getClass().getSimpleName()));
+        return (String) selectKey;
     }
 
     public void removeStartKey() {
diff --git 
a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTest.java
 
b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTest.java
index e63ed52904..b7bd8ce971 100644
--- 
a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTest.java
+++ 
b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTest.java
@@ -24,6 +24,7 @@ import 
org.apache.tinkerpop.gremlin.process.GremlinProcessRunner;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.Path;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.junit.Test;
@@ -52,10 +53,12 @@ import static 
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.or;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.out;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.StringContains.containsString;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -127,6 +130,12 @@ public abstract class WhereTest extends 
AbstractGremlinProcessTest {
 
     public abstract Traversal<Vertex, String> 
get_g_VX3X_asXaX_in_out_asXbX_whereXa_eqXbXX_byXageX_name(final Object v3Id);
 
+    // where(P) with a non-String scope key (invalid usage - value comparisons 
require is(P))
+
+    public abstract Traversal<Vertex, Integer> 
get_g_V_valuesXageX_whereXgtX5XX();
+
+    public abstract Traversal<Vertex, Vertex> 
get_g_V_hasLabelXpersonX_whereX__valuesXageX_whereXgtX5XXX();
+
     @Test
     @LoadGraphWith(MODERN)
     public void 
g_V_hasXageX_asXaX_out_in_hasXageX_asXbX_selectXa_bX_whereXa_eqXbXX() {
@@ -418,6 +427,28 @@ public abstract class WhereTest extends 
AbstractGremlinProcessTest {
         assertThat(traversal.hasNext(), is(false));
     }
 
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_valuesXageX_whereXgtX5XX() {
+        try {
+            get_g_V_valuesXageX_whereXgtX5XX();
+            fail("where(P) with a non-String predicate value should throw an 
IllegalArgumentException at construction");
+        } catch (IllegalArgumentException iae) {
+            assertThat(iae.getMessage(), containsString("use is(P)"));
+        }
+    }
+
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_hasLabelXpersonX_whereX__valuesXageX_whereXgtX5XXX() {
+        try {
+            get_g_V_hasLabelXpersonX_whereX__valuesXageX_whereXgtX5XXX();
+            fail("where(P) with a non-String predicate value should throw an 
IllegalArgumentException at construction");
+        } catch (IllegalArgumentException iae) {
+            assertThat(iae.getMessage(), containsString("use is(P)"));
+        }
+    }
+
 
     public static class Traversals extends WhereTest {
 
@@ -552,5 +583,19 @@ public abstract class WhereTest extends 
AbstractGremlinProcessTest {
         public Traversal<Vertex, String> 
get_g_VX3X_asXaX_in_out_asXbX_whereXa_eqXbXX_byXageX_name(final Object v3Id) {
             return g.V(v3Id).as("a").in().out().as("b").where("a", 
eq("b")).by("age").values("name");
         }
+
+        @Override
+        public Traversal<Vertex, Integer> get_g_V_valuesXageX_whereXgtX5XX() {
+            // gt(5) yields a P whose value is an Integer rather than a String 
scope key; the cast mimics the
+            // erased P<String> that reaches where(P) via raw types, bytecode, 
or deserialization
+            final P<String> nonStringKeyPredicate = (P) gt(5);
+            return g.V().<Integer>values("age").where(nonStringKeyPredicate);
+        }
+
+        @Override
+        public Traversal<Vertex, Vertex> 
get_g_V_hasLabelXpersonX_whereX__valuesXageX_whereXgtX5XXX() {
+            final P<String> nonStringKeyPredicate = (P) gt(5);
+            return 
g.V().hasLabel("person").where(__.values("age").where(nonStringKeyPredicate));
+        }
     }
 }
\ No newline at end of file

Reply via email to