RFC 0 / Strawman

Proposal: Omit fields when their resolver fails (optional execution mode, no new syntax)

Opened on2025-12-04
Updated on2025-12-04

At a glance

WG discussion

Hi all,

I would like to propose an execution-level idea intended to address ambiguity around null values produced by resolver errors in GraphQL responses. This proposal does not introduce any new syntax or type modifiers; it is an optional execution mode that keeps GraphQL fully backwards-compatible.

This discussion is intentionally lightweight — the goal is to validate the idea and get initial feedback before considering a formal RFC.

💡 Proposal (optional execution mode)

If a resolver fails, omit the field entirely from the data response. The failure is reported only in errors[], not as a null value.

This applies to:

  • scalar fields
  • object fields
  • elements of lists
  • nested fields

Null bubbling is skipped in this opt-in mode.

🎯 Problem

When a resolver fails today, GraphQL behaves in one of two ways depending on the field’s nullability:

  1. If the field is nullable, the resolver error produces:
{ "field": null }

and an entry in errors[].

  1. If the field is non-null (!), the specification requires null bubbling:
  • The field itself cannot be returned as null
  • The nearest nullable parent is forced to become null
  • Bubbling continues upward until a nullable parent is found (or the entire data becomes null)

Example:

type Product {
  price: Float!
  name: String
}
type Query {
  product: Product
}

If the price resolver fails, the response must be:

{
  "data": { "product": null },
  "errors": [
    { "message": "timeout", "path": ["product","price"] }
  ]
}

This behavior is mandatory in the current GraphQL specification. Servers cannot avoid bubbling while remaining spec-compliant.

The core issue

A client receiving:

"price": null

cannot distinguish, from the data section alone, whether:

  • the application legitimately returned null (semantic null), or
  • the resolver failed, or etc

Yes, clients can inspect the errors[] array, but in practice it adds complexity

This is the ambiguity the proposal aims to address.

💡 Proposed: optional “omit-on-error” execution mode

If a resolver fails, omit the field entirely from data. The failure is reported only in errors[], not by returning null.

Key points:

  • No changes to schema syntax
  • No additional nullability operators
  • No changes to existing nullability semantics
  • Fully backward-compatible (opt-in)
  • Null bubbling is not performed under this mode

This mode introduces a clearer separation between:

  • semantic nulls, and
  • resolver failures, which become missing fields.

📘 Examples

  1. Nullable field Today:
{
  "data": { "product": { "sku": "SKU1", "price": null } },
  "errors": [
    { "message": "timeout", "path": ["product","price"] }
  ]
}

Proposed:

{
  "data": { "product": {"sku": "SKU1"} },
  "errors": [
    { "message": "timeout", "path": ["product","price"] }
  ]
}
  1. Non-null field (null bubbling vs omission) Today — required null bubbling:
{
  "data": { "product": null },
  "errors": [
    { "message": "timeout", "path": ["product","price"] }
  ]
}

Proposed (in the optional execution mode):

{
  "data": {
    "product": { "sku": "SKU1" }
  },
  "errors": [
    { "message": "timeout", "path": ["product","price"] }
  ]
}

The parent object remains intact. The problematic field is simply omitted.

  1. Lists Return an empty object {} at that index (to preserve list shape) and report the error:
{
  "data": {
    "products": [
      { sku: "SKU1", "price": 1.0 },
      {}
    ]
  },
  "errors": [
    { "message": "failed", "path": ["products",1] }
  ]
}

If only a nested field fails, only that field is omitted:

{
  "data": {
    "products": [
      { sku: "SKU1", "price": 1.0 },
      { sku: "SKU2"}
    ]
  },
  "errors": [
    { "message": "failed", "path": ["products",1, "price"] }
  ]
}

🟩 Benefits

  • Eliminates ambiguity between semantic null and resolver-failure null
  • Allows interpreting data without always correlating with errors[]
  • Makes schema nullability reflect real data semantics
  • Great for typed clients (TypeScript, Flow, Swift, Kotlin)
  • Does not introduce new syntax or type modifiers
  • Backward-compatible as long as it is activated explicitly by the client (per-request opt-in).
  • Easier to reason about partial responses

Timeline