Lei Shu created TINKERPOP-3270:
----------------------------------

             Summary: `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
            Reporter: Lei Shu


### 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