graphql-tools
graphql-tools copied to clipboard
Stitching modifies errors after v8.6.9
Issue workflow progress
Progress of the issue based on the Contributor Workflow
- [ ] 1. The issue provides a reproduction available on Github, Stackblitz or CodeSandbox
Make sure to fork this template and run
yarn generatein the terminal.Please make sure the GraphQL Tools package versions under
package.jsonmatches 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
Something has changed in @graphql-tools/stitch that causes errors to be modified. Custom errors loose their fields and normal errors are getting new fields. I'm struggling to find the reason for it. I also couldn't find anything related in the changelog or code.
Here's how error.originalError looks with @graphql-tools/[email protected] when I log a custom error to the console:
ApiError: Server returned with status code 400
at file:///Users/tobias.reich/Public/bff/packages/api/src/utils/send.js:85:9
request: { ... },
response: { ... }
}
Here's how error.originalError looks with @graphql-tools/[email protected] when I log a custom error to the console:
ApiError: Server returned with status code 400
at file:///Users/tobias.reich/Public/bff/packages/api/src/utils/send.js:85:9 {
path: [ '_createEntityTypeDefinition' ],
locations: undefined,
extensions: [Object: null prototype] {}
}
Gone are request and response. path, locations and extensions have been added. This is the same for normal errors, just that they don't loose their custom fields as they don't have any.
The errors have been logged in the formatError function of apollo-server. The error.originalError should contain the error that has been thrown (at least it did until I updated @graphql-tools/stitch).
Any idea why this is happening?
To Reproduce
- Stitch two schemas
import { stitchSchemas } from '@graphql-tools/stitch'
import {schema as a} from '../sources/a/index.js'
import {schema as b} from '../sources/b/index.js'
export default () => {
return stitchSchemas({
subschemas: [a,b],
mergeTypes: false,
})
}
- Throw an error in a resolver
Mutation: {
_createEntityTypeDefinition: (parent, args, context) => {
throw new Error('Test')
}
}
- Catch and log the original error in
formatError
Expected behavior
The original error shouldn't be modified.
I can confirm we see same behaviour. We are throwing custom errors in our resolvers and in formatError we are extracting some specific information from our errors and forwarding only those...
with 8.6.9 and up we are not getting our errors from resolvers anymore.
Following our contribution flow, would any of you be interested in creating a failing test?
Added failing test: https://github.com/ardatan/graphql-tools/pull/4739
I found we can use error.originalError.originalError to get the actual original error.
Code
index.ts
import { makeExecutableSchema } from '@graphql-tools/schema';
import type { SubschemaConfig } from '@graphql-tools/delegate';
import { ApolloServer } from 'apollo-server';
import { stitchSchemas } from '@graphql-tools/stitch';
class CustomError extends Error {
customField = 1;
}
const typeDefs = `
type Query {
throwError: Boolean!
}
`;
const resolvers = {
Query: {
throwError() {
throw new CustomError();
},
},
};
const subschema: SubschemaConfig = {
schema: makeExecutableSchema({ typeDefs, resolvers }),
};
const { url } = await new ApolloServer({
introspection: process.env.DEBUG === '1',
schema: stitchSchemas({
subschemas: [subschema],
}),
formatError(e) {
console.log(0, e);
console.log(1, e.originalError);
console.log(2, (e.originalError as any)?.originalError);
return e;
},
}).listen({ port: 8080 });
console.log(`Listening at ${url}`);
Output:
0 [GraphQLError] {
locations: undefined,
path: [ 'throwError' ],
extensions: {
code: 'INTERNAL_SERVER_ERROR',
exception: {
message: '',
path: [Array],
locations: undefined,
stacktrace: [Array]
}
}
}
1 Error
at Object.throwError (file:///home/yuki/.local/src/github.com/acomagu/test-apollo-server/index.ts:19:13)
at executeField (file:///home/yuki/.local/src/github.com/acomagu/test-apollo-server/node_modules/@graphql-tools/executor/esm/execution/execute.js:280:24)
at executeFields (file:///home/yuki/.local/src/github.com/acomagu/test-apollo-server/node_modules/@graphql-tools/executor/esm/execution/execute.js:227:28)
at executeOperation (file:///home/yuki/.local/src/github.com/acomagu/test-apollo-server/node_modules/@graphql-tools/executor/esm/execution/execute.js:191:18)
at file:///home/yuki/.local/src/github.com/acomagu/test-apollo-server/node_modules/@graphql-tools/executor/esm/execution/execute.js:48:37
at new ValueOrPromise (/home/yuki/.local/src/github.com/acomagu/test-apollo-server/node_modules/value-or-promise/src/ValueOrPromise.ts:35:15)
at executeImpl (file:///home/yuki/.local/src/github.com/acomagu/test-apollo-server/node_modules/@graphql-tools/executor/esm/execution/execute.js:48:12)
at execute (file:///home/yuki/.local/src/github.com/acomagu/test-apollo-server/node_modules/@graphql-tools/executor/esm/execution/execute.js:34:12)
at ValueOrPromise.then.stopped (file:///home/yuki/.local/src/github.com/acomagu/test-apollo-server/node_modules/@graphql-tools/executor/esm/execution/normalizedExecutor.js:39:37)
at new ValueOrPromise (/home/yuki/.local/src/github.com/acomagu/test-apollo-server/node_modules/value-or-promise/src/ValueOrPromise.ts:35:15) {
path: [ 'throwError' ],
locations: undefined,
extensions: [Object: null prototype] {}
}
2 CustomError
at Object.throwError (file:///home/yuki/.local/src/github.com/acomagu/test-apollo-server/index.ts:19:13)
at executeField (file:///home/yuki/.local/src/github.com/acomagu/test-apollo-server/node_modules/@graphql-tools/executor/esm/execution/execute.js:280:24)
at executeFields (file:///home/yuki/.local/src/github.com/acomagu/test-apollo-server/node_modules/@graphql-tools/executor/esm/execution/execute.js:227:28)
at executeOperation (file:///home/yuki/.local/src/github.com/acomagu/test-apollo-server/node_modules/@graphql-tools/executor/esm/execution/execute.js:191:18)
at file:///home/yuki/.local/src/github.com/acomagu/test-apollo-server/node_modules/@graphql-tools/executor/esm/execution/execute.js:48:37
at new ValueOrPromise (/home/yuki/.local/src/github.com/acomagu/test-apollo-server/node_modules/value-or-promise/src/ValueOrPromise.ts:35:15)
at executeImpl (file:///home/yuki/.local/src/github.com/acomagu/test-apollo-server/node_modules/@graphql-tools/executor/esm/execution/execute.js:48:12)
at execute (file:///home/yuki/.local/src/github.com/acomagu/test-apollo-server/node_modules/@graphql-tools/executor/esm/execution/execute.js:34:12)
at ValueOrPromise.then.stopped (file:///home/yuki/.local/src/github.com/acomagu/test-apollo-server/node_modules/@graphql-tools/executor/esm/execution/normalizedExecutor.js:39:37)
at new ValueOrPromise (/home/yuki/.local/src/github.com/acomagu/test-apollo-server/node_modules/value-or-promise/src/ValueOrPromise.ts:35:15) {
customField: 1
}
could you provide a reproduction on CodeSandbox or StackBlitz?
Closing the issue due to the missing reproduction. If you still have the issue, feel free to create a new one with a reproduction. Thanks!