graphql-yoga icon indicating copy to clipboard operation
graphql-yoga copied to clipboard

log unexpected errors in the server console by default

Open qsona opened this issue 1 year ago • 3 comments

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

  1. Create a minimal app with graphql-yoga, and set context value as a function that throws an error
  2. 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.

qsona avatar Aug 12 '22 06:08 qsona

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 avatar Aug 12 '22 07:08 n1ru4l

@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)

qsona avatar Aug 13 '22 08:08 qsona

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.

lenolib avatar Sep 01 '22 20:09 lenolib

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:

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.

TorbjornHoltmon avatar Oct 30 '22 15:10 TorbjornHoltmon