🌱 This post is still growing and likely will change as best practices evolve 🌳
GraphQL errors are something many of us struggle with. Good practices are emerging but the community has not yet settled on a convention. I hope this guide helps demystify the many ways you can structure errors in your GraphQL servers, and the tradeoffs each of them make.
Stage 1: GraphQL Errors AKA Top-Level Errors
The GraphQL Specification describes errors quite well, so why are they even confusing in the first place?
"message": "Could not resolve to a node with the global id of 'shop-that-does-not-exist'"
❗️Con: No Schema
We love GraphQL for it’s type system. The
errors key of a GraphQL response, commonly called "Top-Level" errors, don't have such schema. They are specified, but introspection tells a client nothing about what might be found in them, they're harder to evolve, and harder to extend. The
extensions key allows providers to add extra fields but then we are out of the specification, and they need to be documented in an ad hoc way, outside of the schema. That's not ideal.
The other potential issue with top-level errors is that when they are present, the corresponding field should be
null. This can potentially be a deal breaker if you're wanting to have errors returned as part of a mutation, but want to query for data on the result anyways. A common example of this is the server sending back the actual state of a resource after a mutation that had errors. With top-level errors this can't be done since the whole mutation field should be
❗️Con: Exceptional Only
“Top-Level” Errors are today generally accepted as a way to represent “exceptional” errors, and errors that are developer facing. [Lee Byron] makes that clear in a few comments on the GraphQL-Spec repository.
GraphQL errors encode exceptional scenarios — like a service being down or some other internal failure. Errors which are part of the API domain should be captured within that domain.
The general philosophy…