You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tinkerpop.apache.org by "Cole Greer (Jira)" <ji...@apache.org> on 2026/07/24 00:29:00 UTC

[jira] [Closed] (TINKERPOP-3270) `where(P)` throws `ClassCastException` for non-String predicate values instead of a descriptive validation error

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

Cole Greer closed TINKERPOP-3270.
---------------------------------
    Fix Version/s: 3.7.7
                   3.8.2
         Assignee: Cole Greer
       Resolution: Fixed

> `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
>            Assignee: Cole Greer
>            Priority: Minor
>             Fix For: 3.7.7, 3.8.2
>
>
> ### 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)