Skip to content

VALIDATION_INVALID_TYPE_VARIABLE error for ID input values overflowing i32 #3873

@SimonSapin

Description

@SimonSapin

Describe the bug
For the ID scalar type, the GraphQL specification defines coercion of input values as:
https://spec.graphql.org/October2021/#sec-ID.Input-Coercion

When expected as an input type, any string (such as "4") or integer (such as 4 or -4) input value should be coerced to ID as appropriate for the ID formats a given GraphQL service expects. Any other input value, including float input values (such as 4.0), must raise a request error indicating an incorrect type.

Apollo Router 1.30.0 implements this as "validate like an input value of type String or Int". The latter is limited to i32:
https://spec.graphql.org/October2021/#sec-Int.Input-Coercion

When expected as an input type, only integer input values are accepted. All other input values, including strings with numeric content, must raise a request error indicating an incorrect type. If the integer input value represents a value less than -2^31 or greater than or equal to 2^31, a request error should be raised.

However no such range is specified for ID. In theory the Router could be made to support integer IDs of arbitrary size. In practice it’s probably unwise to go beyond 53 bits, in case a client or subgraph represents integer like JavaScript does, as floating point with a 53-bit mantissa. Still, it’s easy enough to make the Router support up to i64 here.

To Reproduce
Steps to reproduce the behavior:

  1. Create a /tmp/router.yaml file that contains {}
  2. Run cargo run -- -c /tmp/router.yaml -s examples/graphql/supergraph.graphql
  3. In another terminal, run:
curl -s --request POST \
  --header 'content-type: application/json' \
  --url 'http://127.0.0.1:4000' \
  --data '{"variables": {"var": 2147483648}, "query":"query Q($var: ID!) { topProducts { name reviewsForAuthor(authorID: $var) { id } } }"}'

Expected behavior
The response contains data and no error.

Output
{"errors":[{"message":"invalid type for variable: 'var'","extensions":{"name":"var","code":"VALIDATION_INVALID_TYPE_VARIABLE"}}]}

Additional context
Manually tested fix:

--- a/apollo-router/src/spec/field_type.rs
+++ b/apollo-router/src/spec/field_type.rs
@@ -110,7 +110,7 @@ fn validate_input_value(
         // In practice it seems Int works too
         (hir::Type::Named { name, .. }, Value::String(_)) if name == "ID" => Ok(()),
         (hir::Type::Named { name, .. }, maybe_int) if name == "ID" => {
-            if maybe_int == &Value::Null || maybe_int.is_valid_int_input() {
+            if maybe_int == &Value::Null || maybe_int.as_i64().is_some() {
                 Ok(())
             } else {
                 Err(InvalidValue)

Still needs an automatic test, ideally one checking that 9007199254740993 (2^53 + 1) is passed through to the subgraph without being rounded.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions