graphql-yoga
graphql-yoga copied to clipboard
log unexpected errors in the server console by default
Describe the bug
When an error thrown from context
function, no error logs are shown in standard output/error.
Implementation:
createServer({
// ... ,
context: () => { throw new Error('foo') },
// ...,
})
Then I open the GraphiQL page, the response is
{
"data": null,
"errors": [
{
"message": "Unexpected error."
}
]
}
but no error logs are shown up, so it's hard to find the cause.
I tried useLogger()
and useErrorHandler()
plugins but both didn't catch that error.
Your Example Website or App
https://codesandbox.io/s/summer-brook-tvigl0?file=/src/main.ts
Steps to Reproduce the Bug or Issue
- Create a minimal app with graphql-yoga, and set
context
value as a function that throws an error - Open http://localhost:4000/graphql in your browser, or just send a introspection query
Expected behavior
As a developer, I expected the error messages are shown.
Screenshots or Videos
No response
Platform
- OS: macOS
- NodeJS: 16.10.0
-
@graphql-yoga/*
version(s): 2.5.0, 2.13.6
Additional context
Sorry, I haven't investigate whether this problem is related graphql-yoga or envelop.
Hey @qsona, thank you for using GraphQL Yoga!
Currently, errors are not logged to the console.
The original error SHOULD be included within the errors extension.originalError
field within the execution result sent from the server, when you set the maskedErrors.isDev
to true
(or automatically when process.env.NODE_ENV
is set to 'development'
(See the error masking documentation).
HOWEVER, there is currently a bug within envelop that causes the error message to be swallowed. I am working on a fix of that here:
- https://github.com/n1ru4l/envelop/pull/1471
Let's track this here instead and keep this issue as a general logging issue: https://github.com/dotansimha/graphql-yoga/issues/1585
For now, you can use the following workaround, by specifying your own logger plugin: https://codesandbox.io/s/yoga-log-unexpected-errors-to-the-console-vhir52
We are currently working on GraphQL Yoga v3 (see our roadmap https://github.com/dotansimha/graphql-yoga/issues/1358). We want to make sure that Yoga v3 has the best developer experience. Logging unexpected errors to the console seems like something we should probably do.
In which kind of format would you expect these logs?
@n1ru4l Sorry my report was a bit inaccurate.
On my original app, I'm specifying NODE_ENV=development
and using the useErrorHandler
plugin. The error thrown by context function isn't handled by both, so I created this issue.
The workaround you showed ( onPluginInit(ctx) { ctx.registerContextErrorHandler // ...
) perfectly worked on my app. Thank you very much!
In which kind of format would you expect these logs?
I don't have a strong opinion about log format, but I'm basically satisfied with current way, I mean maskedErrors
option and
useErrorHandler
plugin. I'm thinking that the error thrown by creating context can be regarded as expected, so it just seems better if useErrorHandler
catches it. (It's just an innocent opinion, of course I know it's not easy)
I have a similar problem, where e.g. errors thrown in any callback supplied to plugins loses their stack traces and can be very tedious to track down. This is the line that seems responsible for losing the error stack https://github.com/dotansimha/graphql-yoga/blob/master/packages/common/src/GraphQLYogaError.ts#L36 A typical unhelpful error that gets returned could be:
{
data: null,
errors: [
{
message: "Cannot read properties of undefined (reading 'somewhere_in_my_code')"
}
]
}
It would be great if such errors somehow could be logged, maybe using the debug library.
Hey @qsona, thank you for using GraphQL Yoga!
Currently, errors are not logged to the console.
The original error SHOULD be included within the errors
extension.originalError
field within the execution result sent from the server, when you set themaskedErrors.isDev
totrue
(or automatically whenprocess.env.NODE_ENV
is set to'development'
(See the error masking documentation).HOWEVER, there is currently a bug within envelop that causes the error message to be swallowed. I am working on a fix of that here:
Let's track this here instead and keep this issue as a general logging issue: #1585
For now, you can use the following workaround, by specifying your own logger plugin: https://codesandbox.io/s/yoga-log-unexpected-errors-to-the-console-vhir52
We are currently working on GraphQL Yoga v3 (see our roadmap #1358). We want to make sure that Yoga v3 has the best developer experience. Logging unexpected errors to the console seems like something we should probably do.
In which kind of format would you expect these logs?
I am currently having issues writing error handling with yoga v3. In v2, I could just got the original error from the result, and handle it as I pleased.
In v3 the errors that I throw seems lost.
I have been trying to figgure out when the my error is converted to a GraphQLErorr and the original error lost.
I understand that "maskError" happens after useErrorHandler
, I am just trying to figgure out where I can access my errors.
Within "maskError" the error has already been converted to a GraphQLerror
maskedErrors: {
maskError: (error) => {
console.log(error.name, 'Its a GraphQLError')
// And no properties of the original error exists
console.log(error.originalError.name, 'This is also a GraphQLError...')
console.log(error.originalError.httpErrorMessage, 'Custom error property is gone')
return error as Error
},
},
Using the useErrorHandler
package has the same result.
There are no properties left of the original error that was thrown.
I am using
"graphql-yoga" : "3.0.0-next.8"
"@envelop/core": "^3.0.3"
I am sure the answer is simple, but I think it should be documented how one should catch a custom error thrown in resolvers.
Edit:
After reading up on the documentation, i see that this is intentional. https://www.the-guild.dev/graphql/yoga-server/tutorial/basic/09-error-handling
I understand the design, and I have to rewrite our error handling to support v3. Which is fine.
I did however like the idea of throwing my custom erros from my resolver integrations and having a single place to catch them all. It gave me a central integration to catch and log to external services, and I could control how to mask my errors from there.
Explicit is however better than implicit, so I just have to move my code around.