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

RFC: Add Schema Coordinate to GraphQL Errors

Open PascalSenn opened this issue 2 months ago • 11 comments

Add an optional coordinate field to GraphQL errors that contains the schema coordinate of the object field or field argument associated with the error, enabling direct identification of schema elements that caused runtime errors.

📜 Problem Statement

When a GraphQL error occurs, developers must perform multiple steps to identify which type system member caused the error:

  1. Parse the schema
  2. Parse the operation
  3. Traverse the operation based on the path field in the error

This process is cumbersome and requires tooling to correlate runtime errors back to their schema definitions. While the path field identifies where in the response the error occurred, it doesn't directly indicate which schema element is responsible for the error.

Example

Consider this error response:

{
  "errors": [
    {
      "message": "Name for character with ID 1002 could not be fetched.",
      "locations": [{ "line": 6, "column": 7 }],
      "path": ["hero", "heroFriends", 1, "name"]
    }
  ]
}

To determine that this error originated from the Human.name field in the schema, developers must:

  • Load and parse the schema
  • Parse the GraphQL operation
  • Walk through the operation following the path ["hero", "heroFriends", 1, "name"]
  • Determine the types at each step to identify that heroFriends returns [Friend]
  • Conclude that the error is associated with Human.name

💡 Proposed Solution

Add an optional coordinate field to GraphQL errors that directly references the object fiel or field argument where the error originated.

Example

{
  "errors": [
    {
      "message": "Name for character with ID 1002 could not be fetched.",
      "locations": [{ "line": 6, "column": 7 }],
      "path": ["hero", "heroFriends", 1, "name"],
      "coordinate": "Human.name"
    }
  ]
}

In this example coordinate directly identifies Human.name in the schema as the source, without requiring any parsing or traversal

  1. Simplified Error Tracking: Developers can immediately identify which schema element caused an error without complex analysis.

  2. Better Tooling Support: IDEs, monitoring systems, and debugging tools can directly link errors to schema definitions.

The coordinate field should be included when:

  • An error originates from resolving a specific object field -> object field coordinate
  • An error originates from resolving a specific field argument -> field argument coordinate
  • An error originates from coercing a value of a input object -> field argument of the field that the input object is passed to

The coordinate field may be omitted when:

  • The error is not associated with a specific schema element
  • The server implementation cannot determine the appropriate coordinate

PascalSenn avatar Oct 28 '25 11:10 PascalSenn

Deploy Preview for graphql-spec-draft ready!

Name Link
Latest commit 04e2431a3efc18e3b50b5d0e158631ba7fe6c0b5
Latest deploy log https://app.netlify.com/projects/graphql-spec-draft/deploys/6900a65b5fcd5b0008dafddb
Deploy Preview https://deploy-preview-1200--graphql-spec-draft.netlify.app
Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

netlify[bot] avatar Oct 28 '25 11:10 netlify[bot]

This would really help us simplify error tracking!

n1ru4l avatar Oct 28 '25 11:10 n1ru4l

Adding the schema coordinate together with the existing path expose the schema information. Now the user knows that hero's heroFriends is [Human], and it has name in it. An attacker can predict a lot of information about the schema unsafely by using required argument errors etc too. If you say most clients request __typename anyway, but this is a request which is evaluated by the server, and the resolution of __typename is not the same with exposing the schema coordinate in every error. If we already have __typename + path, we can always find the schema coordinate anyways. So why would we need an extra schema coordinate property in the errors?

ardatan avatar Oct 28 '25 12:10 ardatan

After trying to actually implement walking the path to determine schema coordinate, it appears that the coordinate can be impossible to determine with certitude.

If there is a Union or an Interface involved in the path, you will need to visit the result to know the actual type.

But, in combination with non-nullable field, you have situations where can't determine the actual coordinate.

Example:

#schema.gql

interface Node {
  id: String!,
}

type Query {
  node(id: String!): Node!
}

type User implements Node {
  id: String!,
}

type Comment implements Node {
  id: String!,
}
#query.gql

query {
  node(id: 'a-user-id') {
    id
    __typename
  }
}

If an error occurs in the id resolver, you will get this result:

{ 
  data: null,
  errors: [{
    message: 'An error occured',
    path: ['node', 'id']
  }]
}

Now you have no way to determine if the coordinate is actually User.id or Comment.id. The same applies for Unions.

EmrysMyrddin avatar Oct 28 '25 12:10 EmrysMyrddin

@EmrysMyrddin You're right but the security concern is still there, and if this schema coordinate property will be standard in the error object, then we should document this concern clearly.

ardatan avatar Oct 28 '25 12:10 ardatan

in combination with non-nullable field, you have situations where can't determine the actual coordinate.

@EmrysMyrddin this is yet another use case for onError: NULL and disabling error propagation. At this point error propagation has a bunch of issues (see also https://github.com/graphql/nullability-wg/) so I would rather optimise for the new onError: NULL case.

martinbonnin avatar Oct 28 '25 14:10 martinbonnin

@martinbonnin not sure to entirely understand what you mean with this. From what I understand, you have multiple choices for the execution behavior on error. So I think that whatever the choice you made, you should always be able to know the schema coordinate where the error happened, just as you always now the path at which an error happened.

I hear the security concern, and we should make it obvious the implication of this, just as it has to be obvious the implications of allowing introspection on your schema. We can also recommend to library and server maintainers to mask this by default on production environment, just as unhandled exceptions should be masked by default.

EmrysMyrddin avatar Nov 10 '25 15:11 EmrysMyrddin

whatever the choice you made [for onError], you should always be able to know the schema coordinate where the error happened

@EmrysMyrddin Not sure I agree. I don't want us to keep adding to the spec for mistakes that were made 10 years ago ( and were OK at that time but things have changed, this is a long story).

If you keep using onError: PROPAGATE in 2026 then you can't find the error coordinate for some errors. It's too bad but there is a solution: use onError: NULL and a smart client.

onError: NULL solves this specific issue together with a bunch of other ones (semantic nullability, etc...) all at once 🥳 All of that without adding to the language. It's a win for everyone!

martinbonnin avatar Nov 10 '25 17:11 martinbonnin

I do have my reservations the longer i think about this proposal. I do think it's necessary to have this coordinate as a error for telemetry, but I question the value for the client of it. I would really want to encourage the implementations to map each error to a specific coordinate, hence the proposal, but i am not sure if we need to add it to the response.. What's the value for the client to know that the error happened at Query.foo? How do we approach this?

PascalSenn avatar Nov 10 '25 20:11 PascalSenn

This may just be a feature of graphql/otel-wg

PascalSenn avatar Nov 10 '25 20:11 PascalSenn

In my opinion, coordinate has value on its own, not just for Telemetry, but also for developers to debug an error.

I hear that with this new error propagation mode you can programatically find out the resolver by walking the path. But that's a non-trivial algorithm that you will have to run for each error before being able to report them. While it's straight forward to add it at error construction time, because information is at hand.

And this is only true for programatic usage. If you are a developer, looking at GraphQLError in logs of your application or server, you probably don't have access to the corresponding result data or even just the query document. So you would not be able to disambiguate an error path. Even just finding out the resolver can be tricky if the document contains label.

EmrysMyrddin avatar Nov 14 '25 10:11 EmrysMyrddin