Graphql-tools: Proper error handling [minor changes required]: fixing Object object error messages

Created on 22 Jan 2019  路  7Comments  路  Source: ardatan/graphql-tools

@hwillson for quite a while me and other GraphQL users were dealing with unclear error messages.

To name a few:

https://github.com/graphql-binding/graphql-binding/issues/173
https://github.com/apollographql/graphql-tools/issues/743
(and maybe, but I'm not sure) https://github.com/apollographql/graphql-tools/issues/1037

The impossibility of using custom error codes that Apollo offers and dealing with weird error messages makes it hard to handle errors in a complex application.

Long story short, I guess I've managed to find the possible cause (at line 110):

https://github.com/apollographql/graphql-tools/blob/2394f0c3a8b30dbd4435dd21019727e76e61b892/src/stitching/errors.ts#L104-L113

If the checkResultAndHandleErrors is called and there's an errors array contains only one error the resulting error will be an instance not of Error but rather Object, which will result in unexpected behaviour here - https://github.com/graphql/graphql-js/blob/c2bc19badebd208ff21849e8f579e7034631af42/src/execution/execute.js#L721 as a result of this logic https://github.com/graphql/graphql-js/blob/c2bc19badebd208ff21849e8f579e7034631af42/src/execution/execute.js#L753-L758

In my opinion, the simplest solution would be to have something like this:

  if (result.errors && (!result.data || result.data[responseKey] == null)) {
    // apollo-link-http & http-link-dataloader need the
    // result property to be passed through for better error handling.
    // If there is only one error, which contains a result property, pass the error through
    const newError =
      result.errors.length === 1 && hasResult(result.errors[0])
        // Setting the prototype of result.errors[0] to Error
        ? Object.setPrototypeOf(result.errors[0], Error.prototype)
        : new CombinedError(concatErrors(result.errors), result.errors);
    throw locatedError(newError, info.fieldNodes, responsePathAsArray(info.path));
 } 

bug v5

Most helpful comment

Fix is perfect. Until it lands, I'm using the following equivalent workaround for our remote schemas:

this.link = new ApolloLink((operation: Operation, forward?: NextLink) => {
  return forward(operation).map(data => {
    if(data.errors) {
      for(const error of data.errors) {
        if(!(error instanceof Error))
            Object.setPrototypeOf(error, Error.prototype);
      }
    }

    return data;
  });
}).concat(link);

All 7 comments

Very needed fix!

Yes, this is really needed fix, as I have the same problem and proposed fix solves the problem

Fix is perfect. Until it lands, I'm using the following equivalent workaround for our remote schemas:

this.link = new ApolloLink((operation: Operation, forward?: NextLink) => {
  return forward(operation).map(data => {
    if(data.errors) {
      for(const error of data.errors) {
        if(!(error instanceof Error))
            Object.setPrototypeOf(error, Error.prototype);
      }
    }

    return data;
  });
}).concat(link);

Agreed! The errors keep getting swallowed and it's very annoying to go to the base layer application to try to figure out what the error is.

Any progress with this issue?

We recently released an alpha version of GraphQL Tools (#1308) that should fix the issue.

Please update graphql-tools to next or run:

npx match-version graphql-tools next

Let us know if it solves the problem, we're counting for your feedback! :)

Folded into #1306

Was this page helpful?
0 / 5 - 0 ratings

Related issues

capaj picture capaj  路  4Comments

stubailo picture stubailo  路  3Comments

udisun picture udisun  路  3Comments

brennantaylor picture brennantaylor  路  4Comments

benjaminhon picture benjaminhon  路  3Comments