Supergraph : Single Invalid ID causes all null results

Branch/Environment/Version

  • Branch/Version: v5.1.2
  • Environment: On-prem

Describe the bug
GraphQL unexpected null results. When using a Supergraph with subgraphs (2 or more) that target GraphQL services we have observed issues where a single invalid ID can result in all instances of that object type in the result set being returned as null.

Reproduction steps
This repo contains a complete reproduction of the error
https://gitlab.com/vee-engineering-public/dependencies/tyk-5x-null-reference-bug/-/blob/master/README.md?ref_type=heads

Actual behaviour
Any invalid (does not exist) object ID causes all objects of that type to be null

{
  "data": {
    "posts": {
      "getPosts": [
        {
          "id": "1",
          "title": "post-1",
          "authorId": 9999,
          "user": null <- Should be null
        },
        {
          "id": "2",
          "title": "post-2",
          "authorId": 2,
          "user": null  <- Should *not* be null
        },
        {
          "id": "3",
          "title": "post-3",
          "authorId": 3,
          "user": null <- Should *not* be null
        },
        {
          "id": "4",
          "title": "post-4",
          "authorId": 4,
          "user": null <- Should *not* be null
        }
      ]
    }
  }
}

Expected behaviour
Only objects with invalid IDs should show as null. Other instances should return normally

{
  "data": {
    "posts": {
      "getPosts": [
        {
          "id": "1",
          "title": "post-1",
          "authorId": null,
          "user": null <- This value is correctly returned as null
        },
        {
          "id": "2",
          "title": "post-2",
          "authorId": 2,
          "user": {         <- returned correctly  (not affected by post ID 1 being null)
            "id": "2",
            "name": "user-2"
          }
        },
        {
          "id": "3",
          "title": "post-3",
          "authorId": 3,
          "user": {
            "id": "3",
            "name": "user-3"
          }
        },
        {
          "id": "4",
          "title": "post-4",
          "authorId": 4,
          "user": {
            "id": "4",
            "name": "user-4"
          }
        }
      ]
    }
  }
}

Screenshots/Video
N/A

Logs (debug mode or log file):

time="Oct 10 10:30:26" level=debug msg="/data (beforeFetchHook): {\"method\":\"POST\",\"url\":\"http://users:3000/graphql\",\"header\":{},\"body\":{\"query\":\"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on User {name}}}\",\"variables\":{\"representations\":[{\"id\":\"9999\",\"__typename\":\"User\"},{\"id\":\"2\",\"__typename\":\"User\"},{\"id\":\"3\",\"__typename\":\"User\"},{\"id\":\"4\",\"__typename\":\"User\"}]}}}" api_id=subgraph-users api_name=subgraph-users mw=GraphQLMiddleware org_id=default origin= path="[47 100 97 116 97]"
2023-10-10T10:30:27.017937006Z time="Oct 10 10:30:27" level=debug msg="/data (afterFetchHook.OnData): {\"_entities\":[null,{\"__typename\":\"User\",\"name\":\"user-2\"},{\"__typename\":\"User\",\"name\":\"user-3\"},{\"__typename\":\"User\",\"name\":\"user-4\"}]}" api_id=subgraph-users api_name=subgraph-users mw=GraphQLMiddleware org_id=default origin= path="[47 100 97 116 97]" single_flight=false
2023-10-10T10:30:27.019007048Z time="Oct 10 10:30:27" level=error msg="http: proxy error: Key path not found" api_id=subgraph-users api_name=subgraph-users mw=ReverseProxy org_id=default prefix=proxy server_name="users:3000" user_id=-- user_ip= user_name=
2023-10-10T10:30:27.019548673Z

Configuration (tyk config file):
https://gitlab.com/vee-engineering-public/dependencies/tyk-5x-null-reference-bug/-/blob/master/tyk-v5-1-2/tyk-standalone.conf?ref_type=heads

Additional context
This behaviour was not present in Tyk v4.3.1. There was a different bug on that version that would cause a sort/match/join error if any object id in a result set was returned as null. As per this open issue
Requesting list of records with null foreign key relationship mix up the response and makes data integrity issue · Issue #4353 · TykTechnologies/tyk · GitHub . The workaournd to that was to return dummy IDs (so not null) that did not resolve.

Also tried tykio/tyk-gateway:v5.2.1-rc6-amd64. Same issue

There appears to be another bug in the same area where if the first item is null then the reference resolver receives IDs belonging to the parent entity (The users service receives IDs belonging to posts in this example)

tyk-v5-1-2-tyk-gateway-1       | time="Oct 11 09:32:04" level=debug msg="/data (beforeFetchHook): {\"method\":\"POST\",\"url\":\"http://users:3000/graphql\",\"header\":{},\"body\":{\"query\":\"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on User {name}}}\",\"variables\":{\"representations\":[{\"id\":\"1\",\"__typename\":\"User\"},{\"id\":\"3\",\"__typename\":\"User\"},{\"id\":\"4\",\"__typename\":\"User\"}]}}}" api_id=subgraph-users api_name=subgraph-users mw=GraphQLMiddleware org_id=default origin= path="[47 100 97 116 97]"
tyk-v5-1-2-users-1             | 1
tyk-v5-1-2-users-1             | 3
tyk-v5-1-2-users-1             | 4

authorId 1 set to null.

tyk-v5-1-2-tyk-gateway-1       | time="Oct 11 09:35:27" level=debug msg="/data (beforeFetchHook): {\"method\":\"POST\",\"url\":\"http://users:3000/graphql\",\"header\":{},\"body\":{\"query\":\"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on User {name}}}\",\"variables\":{\"representations\":[{\"id\":\"90001\",\"__typename\":\"User\"},{\"id\":\"90002\",\"__typename\":\"User\"},{\"id\":\"90003\",\"__typename\":\"User\"},{\"id\":\"90004\",\"__typename\":\"User\"}]}}}" api_id=subgraph-users api_name=subgraph-users mw=GraphQLMiddleware org_id=default origin= path="[47 100 97 116 97]"
tyk-v5-1-2-users-1             | 90001
tyk-v5-1-2-users-1             | { id: '90001' }
tyk-v5-1-2-users-1             | 90002
tyk-v5-1-2-users-1             | { id: '90002' }
tyk-v5-1-2-users-1             | 90003
tyk-v5-1-2-users-1             | { id: '90003' }
tyk-v5-1-2-users-1             | 90004
tyk-v5-1-2-users-1             | { id: '90004' }

Hello @Andy_Irvine and welcome to the community :partying_face:

Thanks for filing the bug report. However, I see that the Gitlab link isn’t accessible anymore. Could you open access to it?

If not, then we will try to replicate the issue as best as we can.

If you have more information on the issue e.g. same behaviour on v5.1.0 and v5.1.1 please let us know

Sorry for the late reply.

@Andy_Irvine Are you able to give access to the Gitlab repo?

I cannot reproduce exactly what you experience but I could get something similar with a call to an external subgraph. I see the behaviour has changed from v5.0.0

Hi @Olu . Apologies for the delayed response, I was away on holiday.

The repo visibility has been corrected so you should have the full reproduced error here:

For anyone else that may see this issue: We have had to resort to using Apollo Router to handle all our Supergraph requests. Tyk is still handling REST APIs and the auth for our Graph API but all of the schema management and subgraph routing is now in Apollo Router The Apollo Router - Apollo GraphQL Docs

I’ve logged this as a defect to be looked at in our backlog. Currently GQL federation is not at the top of our priorities, so it might take us a moment to take a longer look at it, but I’ll update here once we have a root cause and/or a fix.