Can't always get extensions property of error in didEncounterErrors


I want to capture errors in the didEncounterErrors hook and persist only some type of errors to my logging service while ignoring other types. What works well is when I import subclasses of the ApolloError class from 'apollo-server-errors' packages (BadUserInputError, ForbiddenError, etc) and throw that error in the resolver. I can then capture that error in didEncounterErrors by doing something like:

plugins: [{
  requestDidStart(ctx) {
    return {
      didEncounterErrors ({ errors }} {
        for (const [_, error] of Object.entries(errors)) {
          if (error.originalError instanceof BadUserInputError) {
            continue; // ignore error
          logger.writeError(error, ctx.context);

however, if the error is thrown by graphql itself, such as a mutation not matching the schema,
error.orginalError is not available in didEncounterErrors. I expect it to be available and it should be of type ValidationError. It is, however, available in formatError. I could handle error logging there, but I’ve read that best practice is to capture errors in didEncounterErrors + you do not have access to context in formatError.

Could anyone explain why when graphql throws a standard validation error, I don’t have access to the extensions property? Is there a way around this?

Pre-execution validation errors are indeed handled by graphql(JS)'s validate function which is invoked by Apollo Server in the request pipeline just after parsing the operation.

When a validation error is observed after invoking validate (as determined by a non-zero length array being returned from validate), we:

  • Invoke any callback that was returned from the validationDidStart hook (that callback is known as “validation did end” and receives an array of GraphQLErrors.
  • Invoke the didEncounterErrors life-cycle hook with the same array of errors.

The native graphql (JS) error is not a ValidationError, which is an Apollo-specific response treatment that currently happens after these life-cycle events.

I admit that it seems plausible to me that that treatment could happen earlier, but it does not today. It’s conceivable to me that if you wanted to pick them up in didEncounterErrors that you could apply your own treatment to those errors in the “Validation did End” hook. There’s some documentation here if you wanted to take a look at how to setup that hook. It’s possible that you could, e.g., attach some additional properties to the error (or its extensions) that you could use in the didEncounterErrors hook. I might suggest something besides ValidationError though, just in case we could eventually make that work natively.

In that spirit, if you’d like for this to happen natively in the future, I’d suggest opening a feature request.

Hope this helps!