graphql-js: Getting multiple instances of graphql error despite only having a single version
I wasn’t sure whether or not to make a new issue or comment on https://github.com/graphql/graphql-js/issues/594 but that one is so old I figured it would be preferable to start anew
In my project I get the “ensure that there are not multiple versions of GraphQL installed in your node_modules directory” error despite having done so.
yarn list output:
yarn list --pattern graphql
yarn list v1.22.5
├─ @apollographql/apollo-tools@0.4.8
├─ @apollographql/graphql-playground-html@1.6.26
├─ @types/graphql-upload@8.0.4
├─ apollo-graphql@0.5.0
├─ graphql-extensions@0.12.4
├─ graphql-scalars@1.2.7
├─ graphql-tag@2.11.0
├─ graphql-tools@4.0.8
├─ graphql-upload@8.1.0
└─ graphql@15.3.0
Done in 0.87s.
and for posterity:
find node_modules -name graphql
node_modules/graphql
My tech stack includes apollo-server-lambda and nexus-schema. Not sure if/how one of them could be behind this, but the issue only cropped up after switching from apollo-server-express to apollo-server-lambda. Nevertheless, it would seem that graphql-js is reporting this error erroneously as I have proven there is only one instance of graphql in my node_modules directory.
exact error message:
Error: Cannot use GraphQLObjectType "Bio" from another module or realm.
Ensure that there is only one instance of "graphql" in the node_modules
directory. If different versions of "graphql" are the dependencies of other
relied on modules, use "resolutions" to ensure only one version is installed.
https://yarnpkg.com/en/docs/selective-version-resolutions
Duplicate "graphql" modules cannot be used at the same time since different
versions may have different capabilities and behavior. The data from one
version used in the function from another could produce confusing and
spurious results.
Link to my project repo: https://github.com/link2cory/portfolio-backend/tree/serverless a quick note: although it is not in the current version of my repo, I have tried making use of the resolutions yarn with exactly the same results. Plus the evidence I have provided above suggests to me that it should not be necessary based on my project dependencies.
Please correct me if I am wrong in any of these assumptions!
About this issue
- Original URL
- State: open
- Created 4 years ago
- Comments: 33 (8 by maintainers)
Commits related to this issue
- update prior agenda items = add time expectations = remove references to cross-realm GraphQL (sadly), see https://github.com/graphql/graphql-js/issues/2801#issuecomment-1154000057 — committed to graphql/graphql-js-wg by yaacovCR 2 years ago
- update prior agenda items (#95) = add time expectations = remove references to cross-realm GraphQL (sadly), see https://github.com/graphql/graphql-js/issues/2801#issuecomment-1154000057 — committed to graphql/graphql-js-wg by yaacovCR 2 years ago
@jkepps It’s been a while since I’ve thought about this but here are a few additional bits of info from what I remember.
We also had to add the following workaround to the vite config:
See this discussion thread. Could be worth considering alternatives within that thread as well.
Another issue we ran into was name shadowing. We had a directory
src/graphqlthat was also being mapped to thegraphqlmodule name and causing issues with vite. Changing the name/mapping fixed the issues there.In our case, we put
.mjsbefore.jsin ourwebpack.config.js:And it worked. That’s black magic.
@link2cory I think I finally discovered the root cause, it happens that serverless-offline uses worker threads to run the lambdas by default. Well, what that means, it means that the the lambda is instantiated in one worker thread and run in a different execution context so the Nexus schemas that are generated in the setup time uses one instance of graphql while the runtime checks after the lambda is setup uses a different instance of graphql.
By setting the following on
serverless.tsit tells the serverless offline plugin that each request should run in a unique process, from setup to execution and in that case it will have the same graphql instance when nexus builds the schema and when graphql-js runs schema. This is similar to what happens in production, the same execution context is used on lambda setup and when requests are processed.If experiencing with vitest, the workaround can be found here https://github.com/vitejs/vite/issues/7879. The config needs to be updated to:
I thought I’d share my own solution here, so it may save someone else hours of headdesking.
My error message was ‘Expected <my schema> to be a GraphQL Schema’ which was traced to the ‘instanceof’ check in
assertSchema.I’d previously added an alias to my webpack config in line with this comment to work around the ‘multiple instances of GraphQL’ issue.
If you add this line, make sure the file extension is
.mjs, not.js, as well as putting the.mjsbefore.jsin theresolve.extensions. IE:EDIT: In fact, once you put
.mjsbefore.js, you can just delete thealias! So that’s probably the best solution. https://github.com/apollographql/apollo-server/issues/4637#issuecomment-882188121Maybe for anyone who’s encountering this issue where you’re seemingly getting this error for no reason. I’ve managed to track down why it was failing for me, and I’ve fixed it.
I got these errors because for some reason Webpack was importing both *.mjs files from graphql, and *.js files. This causes graphql to be instantiated twice, which results in this error. My error was due to the fact that the
graphql-parse-resolve-infopackage is importinggetArgumentValuesfromgraphql/execution/valueswhich Webpack decided to import from the *.js variation instead of the *.mjs one:As can be seen above it was importing the
index.mjsvariation fromgraphqlbut thevalues.jsvariation fromgraphql/execution/values. The fix is to replace thegraphql/execution/valueswith the *.mjs variation:graphql/execution/values.mjs. Which can be done in Webpack by putting the following in your plugins array in your config:Found a workaround, seems like an Apollo Server can fix it, but also it’d be nice if this package could make it a bit easier for people using @yaacovCR’s suggestion.
Not sure why there would be production slowdown, in production we are doing:
value instanceof constructorCould do
value.kind === SCHEMAIs that really slower if use symbol?
In development could do:
value.kind === SCHEMA && value.version === VERSION@davidroeca looks like the alias by itself did the trick. many thanks! 🙏🏽
@onhate thank you!
@onhate THANK YOU so much, you just saved my day! 😄 😄 😄
@onhate thanks so much for diving deep into this. I have verified your solution in my dev environment, and now I wish I had taken a closer look at my deployed lambda because it works just fine (using stock serverless bundler) as your comment lead me to believe it would.
this seems to be quite an edge-case, so I imagine a true solution wont be super fast in the making. In the meantime I will post a link to the commit where I have this working for those who stumble upon this issue before that happens.
https://github.com/link2cory/portfolio-backend/tree/5a450bc1b2fc0e7bddd9192648a3991569273556
Thanks again for your help!
Of course, the instanceOf check is kind of complex…
what the user is trying to do is to make sure that the object is a schema.
But instead what the user does is check that the object is a schema instantiated with the same instance of the constructor for a schema.
but what we want the user to do is to check that the object is a schema instantiated with the same version of the constructor for a schema regardless of instance.
Maybe it makes sense instead to store metadata within the object that can use duck typing to easily check for whether it is a schema or not.
Same goes for the other type system objects…
And metadata can be added to determine what version of GraphQL the schema / type system object was created with…
Just thinking out loud…
Wow thank you so much for your help!