Disabling Error Propagation
GraphQL’s traditional execution behavior propagates an execution error from a non-null field to the nearest nullable parent. This preserves the schema’s strict non-null guarantee, but it can also destroy useful data from the response and make the result unsafe for normalized client caches.
GraphQL.js v17 exposes an experimental operation directive for services and clients that want to test the non-propagating error mode:
directive @experimental_disableErrorPropagation on QUERY | MUTATION | SUBSCRIPTIONWhen an operation uses this directive, an execution error still appears in the
errors list with its normal path, but the errored response position becomes
null directly. The error no longer nulls out non-null parents.
Motivation
The current error behavior proposal describes error propagation as the source of two practical problems: it removes data that could otherwise be used, and it makes errored responses unsafe to write into normalized stores. The broader Semantic Nullability RFC also traces the consequences through partial success, schema design, and normalized caching, and the Nullability WG captured the cache issue as normalized-cache corruption from null bubbling.
The motivations are:
- Preserve useful partial data. A failed field should not necessarily remove sibling response data that resolved successfully.
- Keep normalized caches safe. A bubbled ancestor
nullcan look like a real object update when only one descendant field failed. - Separate execution errors from true semantic nullability. Schema nullability
should be able to express whether
nullis a normal domain value, not whether a resolver might fail.
The core issue behind those motivations is that traditional error propagation couples two concerns:
- Whether
nullis a meaningful value for a field. - Whether resolving that field might fail.
Because any field can fail, schema authors often make fields nullable even when
null is not a normal domain value. This avoids losing larger chunks of the
response when a resolver fails, but it also creates a “nullable epidemic”:
clients and generated types must treat many semantically required values as
nullable just because execution errors are possible.
Error propagation also creates a cache-safety problem for clients with normalized
stores. If viewer.name is already cached and a later query for viewer.age
raises an execution error, traditional propagation may replace the whole
viewer object with null. Writing that bubbled null can corrupt the
normalized cache entry for viewer, even though the already-known name value
is still valid. With propagation disabled, the client can keep the viewer
object, record the error at ["viewer", "age"], and avoid turning a field error
into an ancestor-object cache update.
Disabling error propagation moves responsibility for execution-error handling to
the client. Clients that read errors by path, throw on field errors, use error
boundaries, or store errors alongside normalized data can keep the successful
parts of the response without treating bubbled ancestor null values as real
data.
This also opens the path toward semantic nullability, but with an important
distinction: disabling propagation does not make every raw null in data a
semantic null. A field that raised an execution error is still represented as
null; the errors entry at the same path tells the client that this is an
error null. What changes is that descendant errors no longer replace ancestor
positions, so a null at a position without a matching execution error can more
directly reflect that field’s semantic nullability.
Using it in GraphQL.js
Define the directive in the schema while this feature is experimental:
directive @experimental_disableErrorPropagation on QUERY | MUTATION | SUBSCRIPTION
type Query {
viewer: User!
}
type User {
id: ID!
displayName: String!
nickname: String
}Apply the directive to an operation:
query Profile @experimental_disableErrorPropagation {
viewer {
id
displayName
nickname
}
}If displayName throws, traditional propagation would null out viewer, and
because viewer is non-null, the whole data entry could become null. With
error propagation disabled, GraphQL.js reports the error at the field path and
keeps the rest of the object:
{
"data": {
"viewer": {
"id": "1",
"displayName": null,
"nickname": "Ada"
}
},
"errors": [
{
"message": "Could not fetch display name.",
"path": ["viewer", "displayName"]
}
]
}The directive changes execution behavior only for operations that use it. Operations without the directive keep traditional GraphQL error propagation.
This directive only tests one behavior: error propagation is disabled for the operation. It is not the final shape of the broader standards proposal.
Relationship to onError
The newer draft
onError GraphQL.js implementation
tracks the
error behavior spec
proposal, which generalizes this idea into a client-selected onError behavior.
Rather than only toggling propagation on or off, the proposal describes multiple
modes, including:
- Traditional propagation behavior.
- Resolving errored positions to
nullwithout propagating to non-null parents. - Halting execution on the first execution error.
The current @experimental_disableErrorPropagation directive lets GraphQL.js
users experiment with the second mode. Clients can use it to test error handling
by path, normalized-cache behavior, and UI error boundaries before the request
shape is standardized.
The onError proposal relies on
Service capabilities
because clients need a way to discover support and defaults before choosing a
mode automatically. A client cannot safely assume that a service understands a
new request parameter, supports every proposed mode, or uses the same default
error behavior. Capabilities give tools and clients an in-band way to learn what
the service supports and how to configure themselves without out-of-band
instructions.
Service capabilities and introspection
Service capabilities are proposed as an introspection feature. They were originally part of the error-behavior work and were later extracted into their own Service capabilities proposal. Existing GraphQL introspection describes the schema’s type system: object types, fields, arguments, directives, and related schema metadata. Service capabilities extend that idea to service-level behavior that is outside the type system, such as which experimental syntax, transport features, or error behaviors the service supports.
The proposal introduces a service introspection entry point, currently described
as a __service meta-field, that returns capability records. For error
behavior, those records let a client discover whether the service supports
client-selected onError behavior, which modes are accepted, and what default
mode applies when the request does not choose one.
That distinction matters for clients. A schema can contain the same fields and types whether it uses traditional error propagation or a non-propagating error mode, so ordinary type introspection is not enough to configure the client safely. Capabilities make that operational contract introspectable.
Proposal history
This area has gone through several proposals. The broader Semantic Nullability RFC collects the problem history and solution matrix.
The latest proposals to watch are:
- Error behavior defines
the client-selected
onErrormodes. GraphQL.js v17 makes one part of this current proposal available experimentally through@experimental_disableErrorPropagation: the mode where errored positions resolve tonullwithout propagating through non-null parents. - Service capabilities
is the capabilities work extracted from the error-behavior proposal. It
defines the introspection mechanism for advertising service-level features and
configuration. It is related to error behavior because clients need to
discover whether
onErroris supported, which modes may be requested, and which behavior applies when no mode is requested.
What is next
The current GraphQL.js directive is intentionally experimental and uses an implementation-prefixed name. Future standards work is expected to settle the request shape and discovery story separately:
- The error-behavior proposal defines the execution modes.
- Semantic nullability work defines how schemas and clients distinguish values
that are nullable in normal business logic from values that are only
nullbecause an execution error occurred. - The service-capabilities proposal defines how clients discover whether those modes are supported and what the default behavior is.
Until that settles, clients should only use
@experimental_disableErrorPropagation with services that document support for
it. When it is enabled, clients should treat null at an errored path as an
error null, not as a semantic null.