[ 
https://issues.apache.org/jira/browse/TINKERPOP-3270?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Stephen Mallette updated TINKERPOP-3270:
----------------------------------------
          Component/s: process
    Affects Version/s: 3.7.6
             Priority: Minor  (was: Critical)

> `where(P)` throws `ClassCastException` for non-String predicate values 
> instead of a descriptive validation error
> ----------------------------------------------------------------------------------------------------------------
>
>                 Key: TINKERPOP-3270
>                 URL: https://issues.apache.org/jira/browse/TINKERPOP-3270
>             Project: TinkerPop
>          Issue Type: Bug
>          Components: process
>    Affects Versions: 3.7.6
>            Reporter: Lei Shu
>            Priority: Minor
>
> ### TinkerPop version
> Reproduced on:
> ```text
> TinkerGraph 3.7.0 — gremlin-server (verified 2026-07-12)
> TinkerGraph 3.8.1 — Docker tinkerpop/gremlin-server:latest (image 
> 60673820236b, built 2026-04-07)
> ```
> Source inspection against the 3.8.1 tag confirms the same unconditional 
> `(String)` cast is present.
> ### Environment
> * Host OS: Linux
> * Query language: Gremlin
> * Client: Gremlin Groovy script / gremlin-python WebSocket driver
> ### Description
> `where(P)` accepts a `P<String>` — the predicate value is expected to be a 
> scope key (a String label for a step or variable binding). Value comparisons 
> should use `is(P)` instead.
> When `where(P)` receives a non-string predicate such as `gt(5)`, 
> `WherePredicateStep` construction casts `predicate.getValue()` to `String` 
> without a runtime type check, producing a `ClassCastException`. The failure 
> occurs during step construction, before any data traversing begins; it does 
> not crash the Gremlin Server process.
> Although the Java generic signature is `where(P<String>)`, dynamically typed 
> Gremlin language variants and Gremlin Groovy scripts can construct and submit 
> this traversal at runtime. The raw internal exception obscures the actual API 
> misuse and makes troubleshooting unnecessarily difficult.
> This is not a request to make `where(gt(5))` work as a numeric filter — 
> `is(gt(5))` is the correct API for value comparisons.
> ### To reproduce
> The simplest trigger applies `where(gt(5))` directly to a value stream:
> ```groovy
> __.values('v').where(gt(5))
> // ClassCastException: Integer cannot be cast to String
> //   at WherePredicateStep.getSelectKey(WherePredicateStep.java:105)
> ```
> The same exception occurs when the invalid `where(P)` appears inside a parent 
> `where(Traversal)`:
> ```groovy
> g.V().drop()
> g.addV('X').property('v',10).iterate()
> g.addV('X').property('v',20).iterate()
> g.V().hasLabel('X').where(__.values('v').where(gt(5))).values('v').fold()
> // ClassCastException — same stack trace
> ```
> ### Expected behavior
> The invalid argument should be rejected with a descriptive argument or 
> type-validation exception that identifies the `where(P)` scope-key 
> requirement, rather than exposing an internal `ClassCastException`.
> ### Actual behavior
> `ClassCastException: class java.lang.Integer cannot be cast to class 
> java.lang.String`
> at `WherePredicateStep.getSelectKey(WherePredicateStep.java:105)`
> The exception message gives no indication of what the user did wrong or how 
> to correct it.
> ### Root cause
> During `WherePredicateStep` construction, `configurePredicates()` calls 
> `getSelectKey()`, which casts `predicate.getValue()` to `String` without 
> first validating its runtime type. In 3.8.1 the method has a `Collection` 
> branch as well, but neither path validates that the value selected as the 
> scope key is a `String` before casting:
> ```java
> // WherePredicateStep.java (3.8.1)
> public String getSelectKey(final P<?> predicate) {
>     if (predicate.getValue() instanceof Collection) {
>         // ... existing collection handling ...
>         return (String) ...;
>     }
>     return (String) predicate.getValue();  // line 105 — CCE when value is 
> Integer
> }
> ```
> The cast succeeds when `where(eq('a'))` is used (value = `"a"`, a valid scope 
> key). It fails when `where(gt(5))` is used (value = `5`, an `Integer`).
> ### Suggested fix
> Validate that the value selected by `getSelectKey()` is a `String` before 
> casting. The exact validation location and exception type are left to 
> maintainer discretion.
> ### Workaround
> Use `is()` instead of `where()` for value comparisons:
> ```groovy
> __.values('v').is(gt(5))  // correct
> g.V().hasLabel('X').where(__.values('v').is(gt(5))).values('v').fold()  // → 
> [10, 20]
> ```
> ### Cross-version verification
> | Version | Result |
> |---------|--------|
> | TinkerGraph 3.7.0 | ClassCastException |
> | TinkerGraph 3.8.1 | ClassCastException |
> ### Impact
> This primarily affects diagnostics for dynamically typed clients and remotely 
> submitted traversals. It does not produce incorrect query results, modify 
> data, or terminate the Gremlin Server process. A clear workaround (`is(P)`) 
> exists.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to