ITADN

getBuiltMesh() caches rejected promise permanently, causing all subsequent requests to fail with "Schemas couldn't be generated successfully"

#9326ClosedJacksonDahl2 创建于 2026-03-18
J
JacksonDahl2commented
### Issue workflow progress <!-- PLEASE DO NOT REMOVE THIS SECTION --> _Progress of the issue based on the [Contributor Workflow](https://github.com/the-guild-org/Stack/blob/master/CONTRIBUTING.md#a-typical-contributor-workflow)_ - [ ] 1. The issue provides a reproduction available on [Github](https://github.com/ardatan/graphql-mesh/tree/master/examples/hello-world), [Stackblitz](https://stackblitz.com/github/ardatan/graphql-mesh/tree/master/examples/hello-world) or [CodeSandbox](https://codesandbox.io/s/github/ardatan/graphql-mesh/tree/master/examples/hello-world) > Make sure to fork this template and run `yarn generate` in the terminal. > > Please make sure Mesh package versions under `package.json` matches yours. - [ ] 2. A failing test has been provided - [ ] 3. A local solution has been provided - [ ] 4. A pull request is pending review --- **Describe the bug** When `getMesh()` fails during initialization (e.g. a transient network error fetching a remote schema), the rejected promise is stored in `meshInstance$` and never cleared. Every subsequent request to that process returns the cached rejection, the service never recovers without a full restart. With fork > 1, this creates intermittent 500s: workers that happened to initialize successfully continue serving requests, while workers whose first initialization failed are permanently broken. From the outside this looks like a random 50% (or 25%, 75%, etc.) failure rate that "fixes itself" on reload. **To Reproduce** Steps to reproduce the behavior: 1. Configure a GraphQL Mesh service with fork: 4 and a remote source handler (e.g. fetching SDL from GraphQL Hive CDN) 2. Simulate a transient failure on startup for one or more workers (network blip, upstream timeout, etc.) 3. Observe that affected workers return 500 indefinitely with: ```bash Error: Schemas couldn't be generated successfully. Check for the logs by running Mesh with DEBUG=1 environmental variable to get more verbose output. at getMesh (file:///app/node_modules/@graphql-mesh/runtime/esm/get-mesh.js:118:15) ``` **Expected behavior** If getMesh() rejects, meshInstance$ should be reset to undefined so the next incoming request triggers a fresh initialization attempt. **Root cause** The auto-generated `getBuiltMesh()` in `.mesh/index.ts` assigns the initialization promise to the module-level `meshInstance$` but has no `.catch()` on that assignment: ```typescript let meshInstance$: Promise<MeshInstance> | undefined; export function getBuiltMesh(): Promise<MeshInstance> { if (meshInstance$ == null) { // ... meshInstance$ = getMeshOptions() .then(meshOptions => getMesh(meshOptions)) .then(mesh => { const id = mesh.pubsub.subscribe('destroy', () => { meshInstance$ = undefined; // only resets on graceful destroy mesh.pubsub.unsubscribe(id); }); return mesh; }); // ← no .catch() — rejected promise is cached here permanently } return meshInstance$; // ← returns the rejected promise on every subsequent call } ``` When the promise rejects, meshInstance$ is set to the rejected promise. On the next request, `meshInstance$ == null` is false (a rejected Promise is not null), so the guard never triggers a retry. The rejected promise is returned forever. **Environment:** - @graphql-mesh/cli: 0.100.26 - @graphql-mesh/runtime: (via @graphql-mesh/cli) - @graphql-mesh/graphql: 0.97.5 - Node.js, fork: 4 - Remote source: GraphQL Hive CDN SDL **Additional context** <!-- Add any other context about the problem here. -->
关闭于 2026-03-18 1 条评论