Could not plan the operation missing path
I have a federated graph using a version of the federation example as my gateway.
Most of my backends extend the Company-type and add fields to it.
Some queries now fails with the below error but not all and I see no pattern to which fail and which succeed. In some cases it's even different for queries which target the same backend that behaves differently.
internal: bad datasource configuration - could not plan the operation. missing path: [query.company.__typename]
What might be the problem? What can I do to provide more information to identify the problem?
Reverting back to github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.46 seems to make it behave correctly again.
Can you publish a test or example that triggers the issue?
Would love to. Not sure really were to begin since I'm not sure what is causing the problem though. Currently looking through the diff between rc.46 and rc.49 to get some kind if hint. :-)
Hi @argoyle will it be possible for you to share subgraphs involved in your query and query itself?
e.g. try to cut subgraphs and query to the smalles reproducible amount
Sure thing.
Failing query:
curl 'http://localhost:4444/query' \
-H 'Accept-Language: en,sv;q=0.9,en-US;q=0.8' \
-H 'Cache-Control: no-cache' \
-H 'Connection: keep-alive' \
-H 'DNT: 1' \
-H 'Origin: http://localhost:3300' \
-H 'Pragma: no-cache' \
-H 'Referer: http://localhost:3300/' \
-H 'Sec-Fetch-Dest: empty' \
-H 'Sec-Fetch-Mode: cors' \
-H 'Sec-Fetch-Site: same-site' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36' \
-H 'accept: */*' \
-H 'authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI...<redacted>' \
-H 'content-type: application/json' \
-H 'sec-ch-ua: "Not/A)Brand";v="8", "Chromium";v="126"' \
-H 'sec-ch-ua-mobile: ?0' \
-H 'sec-ch-ua-platform: "macOS"' \
--data-raw $'{"operationName":"EntrySeries","variables":{"companyId":"018f88a0-f02d-701b-ba35-126a347ad77f"},"query":"query EntrySeries($companyId: ID\u0021) {\\n company(id: $companyId) {\\n id\\n entrySeries {\\n ...entrySeries\\n __typename\\n }\\n __typename\\n }\\n}\\n\\nfragment entrySeries on EntrySeries {\\n id\\n name\\n __typename\\n}"}'
Working query (running from same frontend-page more or less in parallell):
curl 'http://localhost:4444/query' \
-H 'Accept-Language: en,sv;q=0.9,en-US;q=0.8' \
-H 'Cache-Control: no-cache' \
-H 'Connection: keep-alive' \
-H 'DNT: 1' \
-H 'Origin: http://localhost:3300' \
-H 'Pragma: no-cache' \
-H 'Referer: http://localhost:3300/' \
-H 'Sec-Fetch-Dest: empty' \
-H 'Sec-Fetch-Mode: cors' \
-H 'Sec-Fetch-Site: same-site' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36' \
-H 'accept: */*' \
-H 'authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI...<redacted>' \
-H 'content-type: application/json' \
-H 'sec-ch-ua: "Not/A)Brand";v="8", "Chromium";v="126"' \
-H 'sec-ch-ua-mobile: ?0' \
-H 'sec-ch-ua-platform: "macOS"' \
--data-raw $'{"operationName":"FiscalYears","variables":{"companyId":"018f88a0-f02d-701b-ba35-126a347ad77f"},"query":"query FiscalYears($companyId: ID\u0021) {\\n company(id: $companyId) {\\n id\\n fiscalYears {\\n id\\n start\\n end\\n __typename\\n }\\n __typename\\n }\\n}"}'
company-service schema:
type Company @key(fields: "id") {
id: ID!
name: String!
}
type Query @extends {
companies: [Company!]!
company(id: ID!): Company!
}
accounting-service schema:
directive @goField(
forceResolver: Boolean
name: String
) on INPUT_FIELD_DEFINITION | FIELD_DEFINITION
type Company @key(fields: "id") @extends {
id: ID!
entrySeries: [EntrySeries!]! @goField(forceResolver: true)
fiscalYears: [FiscalYear!]! @goField(forceResolver: true)
}
type EntrySeries {
id: ID!
name: String!
}
type FiscalYear {
id: ID!
start: String!
end: String!
}
I have six other subgraphs which also extend the Company type in an identical manner but with other fields of course.
I noticed this in the diff between rc.46 and rc.49:
Could it be that the planning visitor is being used by multiple requests at the same time somehow and the objects and field become reset mid-planning in some of the requests?
Hmmm, no, there is a mutex before that of course. It's iterating until it has tried 100 times without finding the field.
Hmmm, the problem seems to be that when using a fragment spread in Apollo, __typename is automatically included in the query and that messes up the planning. Hope that gives an indication on how to resolve the issue.
It's most definitely the fact that a fragment is present. Just including __typename in the query works correctly.
@jensneuse @devsergiy Added a reproduction test in #837
Or more correct, I just added __typename to an existing test which made it fail with "my" error. 😊
Enabling loads of Planner debug-config it seems to lose __typename when in the ConfigurationVisitor:
Initial node suggestions:
{"ds":0,"path":"query.hero","typeName":"Query","fieldName":"hero","isRootNode":true, "isSelected": true,"select reason": []}
{"ds":0,"path":"query.hero.name","typeName":"Character","fieldName":"name","isRootNode":false, "isSelected": true,"select reason": []}
{"ds":0,"path":"query.hero.__typename","typeName":"Character","fieldName":"__typename","isRootNode":false, "isSelected": true,"select reason": []}
[configurationVisitor]: EnterSelectionSet ref: 2
[configurationVisitor]: EnterField ref: 2 fieldName: hero typeName: Query
[configurationVisitor]: saveAddedPath {"ds":0,"path":"query","shouldWalkFields":true,"pathType":"parent"}
[configurationVisitor]: saveAddedPath {"ds":0,"path":"query.hero","fieldRef": 2,"typeName":"Query","shouldWalkFields":true,"isRootNode":true,"pathType":"field"}
[configurationVisitor]: EnterSelectionSet ref: 1
[configurationVisitor]: EnterField ref: 3 fieldName: name typeName: Character
[configurationVisitor]: saveAddedPath {"ds":0,"path":"query.hero.name","fieldRef": 3,"typeName":"Character","shouldWalkFields":true,"isRootNode":false,"pathType":"field"}
[configurationVisitor]: LeaveField ref: 3 fieldName: name typeName: Character
[configurationVisitor]: EnterField ref: 4 fieldName: __typename typeName: Character
[configurationVisitor]: LeaveField ref: 4 fieldName: __typename typeName: Character
[configurationVisitor]: LeaveSelectionSet ref: 1
[configurationVisitor]: LeaveField ref: 2 fieldName: hero typeName: Query
[configurationVisitor]: LeaveSelectionSet ref: 2
Operation after initial run:
{
hero {
name
__typename
}
}
Planning paths after initial run
Should revisit: true
Has new fields: false
Has missing paths: true
Has fields waiting for dependency: false
Missing paths:
query.hero.__typename
And then it iterates 100 times with similar output.
Hmmm, that might be due to the FakePlanner having a PlanningBehavior that doesn't include typename though. If I modify that it seems to be planning correctly. Back to digging again.
Ok, perhaps one more nugget of information. Each query works on it's own as long as my two subscriptions have not already ran. If I run my three queries from Insomnia directly after starting the federation gateway they also work from my Vue-app including the subscriptions. 🙈
It's my subscription which return the Company-type that is causing the problem.
Which also introduces a third subgraph which extend the Company-type. I'll try to modify my current test to also plan the subscription first.
Still unable to reproduce this in a test 🙁 It's losing the Company.__typename in the secondary run for some reason.
If I add the Company.name to the queries it magically starts to work again. So the problem only exists if I select the key, __typename as well as whatever the other subgraph has extended the Company-type with. As said in an earlier comment this was introduced in rc47.
Adding Company.name would then of course introduce an extra call to the company subgraph which would not really be needed since both id and __typename should be available from any of the already used subgraphs. I'm still at loss of what the problem is here. Would @devsergiy have any thoughts on what part of the rc47 changes might be related?
Here is a 15k lines log with loads of debug-data. To me it looks like it should find Company.__typename in the first planner but still it claims that it's missing. The log also contains the log for the subscription which makes it fail. goland.log
Hmmm, on the other hand it seems to want to get __typename from another DS (12485775574321252452) which is not part of any of the two planners (5424679272531918615 and 6927017134761466251).
In the second run.
Initial nodes:
{"ds":5424679272531918615,"path":"query.company.__typename","typeName":"Company","fieldName":"__typename","isRootNode":true, "isSelected": true,"select reason": [stage2: node on the same source as selected parent]} nodes after applying hints
And then after applying hints:
{"ds":12485775574321252452,"path":"query.company.__typename","typeName":"Company","fieldName":"__typename","isRootNode":true, "isSelected": true,"select reason": [provided by planner as required by @key]}
Not sure why it's changing DS at that point. The DS it's selecting is the main one used in the subscription though.
If I exclude __typename like this it works: https://github.com/wundergraph/graphql-go-tools/pull/847
Not sure what I break by doing it though.
Hi @argoyle
sorry for the big delay
could you try out a version from this PR I believe it should fix your problems with a typenames
Thanks, Wundergraph Team
No worries at all. That one works perfectly! 🎉 🚀
Looking forward to a future release. Thanks @devsergiy and the rest of the Wundergraph team. ❤️