• Docs
  • Errors

Errors

Custom Errors

Shield, by default, catches all errors thrown during resolver execution. This way we can be 100% sure none of your internal logic can be exposed to the client if it was not meant to be.

To return custom error messages to your client, you can return error instead of throwing it. This way, Shield knows it's not a bug but rather a design decision under control. Besides returning an error you can also return a string representing a custom error message.

You can return custom error from resolver or from rule itself. Rules that return error are treated as failing, therefore not processing any further resolvers.

const typeDefs = /* GraphQL */ `
  type Query {
    customErrorInResolver: String
    customErrorInRule: String
  }
`
 
const resolvers = {
  Query: {
    customErrorInResolver() {
      return new Error('Custom error message from resolver.')
    },
    customErrorMessageInRule() {
      // Querying is stopped because rule returns an error
      console.log("This won't be logged.")
      return "you won't see me!"
    },
    customErrorInRule() {
      // Querying is stopped because rule returns an error
      console.log("This won't be logged.")
      return "you won't see me!"
    },
  },
}
 
const ruleWithCustomError = rule()(async (parent, args, ctx, info) => {
  return new Error('Custom error from rule.')
})
 
const ruleWithCustomErrorMessage = rule()(async (parent, args, ctx, info) => {
  return 'Custom error message from rule.'
})
 
const permissions = shield({
  Query: {
    customErrorInRule: ruleWithCustomError,
    customErrorMessageInRule: ruleWithCustomErrorMessage,
  },
})
 
const server = GraphQLServer({
  typeDefs,
  resolvers,
  middlewares: [permissions],
})
💡

Errors thrown in resolvers can be tracked using debug option. This way Shield ensures your code is production ready at all times.

💡

If you wish to see errors thrown inside resolvers, you can set allowExternalErrors option to true. This way, Shield won't hide custom errors thrown during query resolving.

Global Fallback Error

GraphQL Shield allows you to set a globally defined fallback error that is used instead of Not Authorised! default response. This might be particularly useful for localization. You can use string or even custom Error to define it.

const permissions = shield(
  {
    Query: {
      items: allow,
    },
  },
  {
    fallbackError: 'To je napaka!', // meaning "This is a mistake" in Slovene.
  },
)
 
const permissions = shield(
  {
    Query: {
      items: allow,
    },
  },
  {
    fallbackError: new CustomError('You are something special!'),
  },
)
 
const permissions = shield(
  {
    Query: {
      items: allow,
    },
  },
  {
    async fallbackError(thrownThing, parent, args, context, info) {
      if (thrownThing instanceof ApolloError) {
        // expected errors
        return thrownThing
      }
      if (thrownThing instanceof Error) {
        // unexpected errors
        console.error(thrownThing)
        await Sentry.report(thrownThing)
        return new ApolloError('Internal server error', 'ERR_INTERNAL_SERVER')
      }
      // what the hell got thrown
      console.error('The resolver threw something that is not an error.')
      console.error(thrownThing)
      return new ApolloError('Internal server error', 'ERR_INTERNAL_SERVER')
    },
  },
)
Last updated on October 10, 2022