1(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[4656],{7750:function(e,i,s){(window.__NEXT_P=window.__NEXT_P||[]).push(["/docs/disabling-error-propagation",function(){return s(8750)}])},8750:function(e,i,s){"use strict";s.r(i),s.d(i,{useTOC:function(){return h}});var n=s(5893),r=s(7812),a=s(3412),t=s(8925),l=s(5192);function h(e){let i={code:"code",...(0,t.a)()};return[{value:"Motivation",id:"motivation",depth:2},{value:"Using it in GraphQL.js",id:"using-it-in-graphqljs",depth:2},{value:(0,n.jsxs)(n.Fragment,{children:["Relationship to ",(0,n.jsx)(i.code,{children:"onError"})]}),id:"relationship-to-onerror",depth:2},{value:"Service capabilities and introspection",id:"service-capabilities-and-introspection",depth:2},{value:"Proposal history",id:"proposal-history",depth:2},{value:"What is next",id:"what-is-next",depth:2}]}i.default=(0,r.c)(function(e){let{toc:i=h(e)}=e,s={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",span:"span",ul:"ul",...(0,t.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.h1,{children:"Disabling Error Propagation"}),"\n",(0,n.jsx)(s.p,{children:"GraphQLâs traditional execution behavior propagates an execution error from a\nnon-null field to the nearest nullable parent. This preserves the schemaâs\nstrict non-null guarantee, but it can also destroy useful data from the response\nand make the result unsafe for normalized client caches."}),"\n",(0,n.jsx)(s.p,{children:"GraphQL.js v17 exposes an experimental operation directive for services and\nclients that want to test the non-propagating error mode:"}),"\n",(0,n.jsx)(s.pre,{icon:l.Wo,tabIndex:"0","data-language":"graphql","data-word-wrap":"",children:(0,n.jsx)(s.code,{children:(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"directive"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" @experimental_disableErrorPropagation"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" on"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" QUERY"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" | "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"MUTATION"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" | "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"SUBSCRIPTION"})]})})}),"\n",(0,n.jsxs)(s.p,{children:["When an operation uses this directive, an execution error still appears in the\n",(0,n.jsx)(s.code,{children:"errors"})," list with its normal ",(0,n.jsx)(s.code,{children:"path"}),", but the errored response position becomes\n",(0,n.jsx)(s.code,{children:"null"})," directly. The error no longer nulls out non-null parents."]}),"\n",(0,n.jsx)(s.h2,{id:i[0].id,children:i[0].value}),"\n",(0,n.jsxs)(s.p,{children:["The current\n",(0,n.jsx)(s.a,{href:"https://github.com/graphql/graphql-spec/pull/1163",children:"error behavior"})," proposal\ndescribes error propagation as the source of two practical problems: it removes\ndata that could otherwise be used, and it makes errored responses unsafe to\nwrite into normalized stores. The broader\n",(0,n.jsx)(s.a,{href:"https://github.com/graphql/graphql-wg/blob/main/rfcs/SemanticNullability.md",children:"Semantic Nullability RFC"}),"\nalso traces the consequences through partial success, schema design, and\nnormalized caching, and the Nullability WG captured the cache issue as\n",(0,n.jsx)(s.a,{href:"https://github.com/graphql/nullability-wg/issues/20",children:"normalized-cache corruption from null bubbling"}),"."]}),"\n",(0,n.jsx)(s.p,{children:"The motivations are:"}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsx)(s.li,{children:"Preserve useful partial data. A failed field should not necessarily remove\nsibling response data that resolved successfully."}),"\n",(0,n.jsxs)(s.li,{children:["Keep normalized caches safe. A bubbled ancestor ",(0,n.jsx)(s.code,{children:"null"})," can look like a real\nobject update when only one descendant field failed."]}),"\n",(0,n.jsxs)(s.li,{children:["Separate execution errors from true semantic nullability. Schema nullability\nshould be able to express whether ",(0,n.jsx)(s.code,{children:"null"}
1)," is a normal domain value, not whether\na resolver might fail."]}),"\n"]}),"\n",(0,n.jsx)(s.p,{children:"The core issue behind those motivations is that traditional error propagation\ncouples two concerns:"}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsxs)(s.li,{children:["Whether ",(0,n.jsx)(s.code,{children:"null"})," is a meaningful value for a field."]}),"\n",(0,n.jsx)(s.li,{children:"Whether resolving that field might fail."}),"\n"]}),"\n",(0,n.jsxs)(s.p,{children:["Because any field can fail, schema authors often make fields nullable even when\n",(0,n.jsx)(s.code,{children:"null"})," is not a normal domain value. This avoids losing larger chunks of the\nresponse when a resolver fails, but it also creates a ânullable epidemicâ:\nclients and generated types must treat many semantically required values as\nnullable just because execution errors are possible."]}),"\n",(0,n.jsxs)(s.p,{children:["Error propagation also creates a cache-safety problem for clients with normalized\nstores. If ",(0,n.jsx)(s.code,{children:"viewer.name"})," is already cached and a later query for ",(0,n.jsx)(s.code,{children:"viewer.age"}
1),"\nraises an execution error, traditional propagation may replace the whole\n",(0,n.jsx)(s.code,{children:"viewer"})," object with ",(0,n.jsx)(s.code,{children:"null"}),". Writing that bubbled ",(0,n.jsx)(s.code,{children:"null"})," can corrupt the\nnormalized cache entry for ",(0,n.jsx)(s.code,{children:"viewer"}),", even though the already-known ",(0,n.jsx)(s.code,{children:"name"})," value\nis still valid. With propagation disabled, the client can keep the ",(0,n.jsx)(s.code,{children:"viewer"}),"\nobject, record the error at ",(0,n.jsx)(s.code,{children:'["viewer", "age"]'}),", and avoid turning a field error\ninto an ancestor-object cache update."]}),"\n",(0,n.jsxs)(s.p,{children:["Disabling error propagation moves responsibility for execution-error handling to\nthe client. Clients that read ",(0,n.jsx)(s.code,{children:"errors"})," by path, throw on field errors, use error\nboundaries, or store errors alongside normalized data can keep the successful\nparts of the response without treating bubbled ancestor ",(0,n.jsx)(s.code,{children:"null"})," values as real\ndata."]}),"\n",(0,n.jsxs)(s.p,{children:["This also opens the path toward semantic nullability, but with an important\ndistinction: disabling propagation does not make every raw ",(0,n.jsx)(s.code,{children:"null"})," in ",(0,n.jsx)(s.code,{children:"data"})," a\nsemantic ",(0,n.jsx)(s.code,{children:"null"}),". A field that raised an execution error is still represented as\n",(0,n.jsx)(s.code,{children:"null"}),"; the ",(0,n.jsx)(s.code,{children:"errors"})," entry at the same path tells the client that this is an\nerror ",(0,n.jsx)(s.code,{children:"null"}),". What changes is that descendant errors no longer replace ancestor\npositions, so a ",(0,n.jsx)(s.code,{children:"null"})," at a position without a matching execution error can more\ndirectly reflect that fieldâs semantic nullability."]}),"\n",(0,n.jsx)(s.h2,{id:i[1].id,children:i[1].value}),"\n",(0,n.jsx)(s.p,{children:"Define the directive in the schema while this feature is experimental:"}),"\n",(0,n.jsx)(s.pre,{icon:l.Wo,tabIndex:"0","data-language":"graphql","data-word-wrap":"",children:(0,n.jsxs)(s.code,{children:[(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"directive"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" @experimental_disableErrorPropagation"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:" on"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" QUERY"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" | "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"MUTATION"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" | "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"SUBSCRIPTION"})]}),"\n",(0,n.jsx)(s.span,{children:" "}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"type"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" Query"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#E36209","--shiki-dark":"#FFAB70"},children:" viewer"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"User"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"!"})]}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})}),"\n",(0,n.jsx)(s.span,{children:" "}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"type"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:" User"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#E36209","--shiki-dark":"#FFAB
170"},children:" id"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"ID"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"!"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#E36209","--shiki-dark":"#FFAB70"},children:" displayName"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"!"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#E36209","--shiki-dark":"#FFAB70"},children:" nickname"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"String"})]}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,n.jsx)(s.p,{children:"Apply the directive to an operation:"}),"\n",(0,n.jsx)(s.pre,{icon:l.Wo,tabIndex:"0","data-language":"graphql","data-word-wrap":"",children:(0,n.jsxs)(s.code,{children:[(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"},children:"query"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" Profile"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"},children:" @experimental_disableErrorPropagation"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#E36209","--shiki-dark":"#FFAB70"},children:" viewer"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#E36209","--shiki-dark":"#FFAB70"},children:" id"})}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#E36209","--shiki-dark":"#FFAB70"},children:" displayName"})}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#E36209","--shiki-dark":"#FFAB70"},children:" nickname"})}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" }"})}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,n.jsxs)(s.p,{children:["If ",(0,n.jsx)(s.code,{children:"displayName"}
1)," throws, traditional propagation would null out ",(0,n.jsx)(s.code,{children:"viewer"}),", and\nbecause ",(0,n.jsx)(s.code,{children:"viewer"})," is non-null, the whole ",(0,n.jsx)(s.code,{children:"data"})," entry could become ",(0,n.jsx)(s.code,{children:"null"}),". With\nerror propagation disabled, GraphQL.js reports the error at the field path and\nkeeps the rest of the object:"]}),"\n",(0,n.jsx)(s.pre,{tabIndex:"0","data-language":"json","data-word-wrap":"",children:(0,n.jsxs)(s.code,{children:[(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"{"})}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:' "data"'}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": {"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:' "viewer"'}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": {"})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:' "id"'}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:'"1"'}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:' "displayName"'}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:"null"}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:' "nickname"'}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:'"Ada"'})]}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" }"})}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" },"})}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:' "errors"'}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": ["})]}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:' "message"'}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:'"Could not fetch display name."'}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:","})]}),"\n",(0,n.jsxs)(s.span,{children:[(0,n.jsx)(s.span,{style:{"--shiki-light":"#005CC5","--shiki-dark":"#79B8FF"},children:' "path"'}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:": ["}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:'"viewer"'}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"},children:'"displayName"'}),(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"]"})]}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" }"})}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:" ]"})}),"\n",(0,n.jsx)(s.span,{children:(0,n.jsx)(s.span,{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})}),"\n",(0,n.jsx)(s.p,{children:"The directive changes execution behavior only for operations that use it.\nOperations without the directive keep traditional GraphQL error propagation."}),"\n",(0,n.jsx)(s.p,{children:"This directive only tests one behavior: error propagation is disabled for the\noperation. It is not the final shape of the broader standards proposal."}),"\n",(0,n.jsx)(s.h2,{id:i[2].id,children:i[2].value}),"\n",(0,n.jsxs)(s.p,{children:["The newer draft\n",(0,n.jsxs)(s.a,{href:"https://github.com/graphql/graphql-js/pull/4364",children:[(0,n.jsx)(s.code,{children:"onError"})," GraphQL.js implementation"]}),"\ntracks the\n",(0,n.jsx)(s.a,{href:"https://github.com/graphql/graphql-spec/pull/1163",children:"error behavior"})," spec\nproposal, which generalizes this idea into a client-selected ",(0,n.jsx)(s.code,{children:"onError"})," behavior.\nRather than only toggling propagation on or off, the proposal describes multiple\nmodes, including:"]}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsx)(s.li,{children:"Traditional prop
1agation behavior."}),"\n",(0,n.jsxs)(s.li,{children:["Resolving errored positions to ",(0,n.jsx)(s.code,{children:"null"})," without propagating to non-null parents."]}),"\n",(0,n.jsx)(s.li,{children:"Halting execution on the first execution error."}),"\n"]}),"\n",(0,n.jsxs)(s.p,{children:["The current ",(0,n.jsx)(s.code,{children:"@experimental_disableErrorPropagation"})," directive lets GraphQL.js\nusers experiment with the second mode. Clients can use it to test error handling\nby path, normalized-cache behavior, and UI error boundaries before the request\nshape is standardized."]}),"\n",(0,n.jsxs)(s.p,{children:["The ",(0,n.jsx)(s.code,{children:"onError"})," proposal relies on\n",(0,n.jsx)(s.a,{href:"https://github.com/graphql/graphql-spec/pull/1208",children:"Service capabilities"}),"\nbecause clients need a way to discover support and defaults before choosing a\nmode automatically. A client cannot safely assume that a service understands a\nnew request parameter, supports every proposed mode, or uses the same default\nerror behavior. Capabilities give tools and clients an in-band way to learn what\nthe service supports and how to configure themselves without out-of-band\ninstructions."]}),"\n",(0,n.jsx)(s.h2,{id:i[3].id,children:i[3].value}),"\n",(0,n.jsxs)(s.p,{children:["Service capabilities are proposed as an introspection feature. They were\noriginally part of the error-behavior work and were later extracted into their\nown ",(0,n.jsx)(s.a,{href:"https://github.com/graphql/graphql-spec/pull/1208",children:"Service capabilities"}),"\nproposal. Existing GraphQL introspection describes the schemaâs type system:\nobject types, fields, arguments, directives, and related schema metadata. Service\ncapabilities extend that idea to service-level behavior that is outside the type\nsystem, such as which experimental syntax, transport features, or error\nbehaviors the service supports."]}),"\n",(0,n.jsxs)(s.p,{children:["The proposal introduces a service introspection entry point, currently described\nas a ",(0,n.jsx)(s.code,{children:"__service"})," meta-field, that returns capability records. For error\nbehavior, those records let a client discover whether the service supports\nclient-selected ",(0,n.jsx)(s.code,{children:"onError"})," behavior, which modes are accepted, and what default\nmode applies when the request does not choose one."]}),"\n",(0,n.jsx)(s.p,{children:"That distinction matters for clients. A schema can contain the same fields and\ntypes whether it uses traditional error propagation or a non-propagating error\nmode, so ordinary type introspection is not enough to configure the client\nsafely. Capabilities make that operational contract introspectable."}),"\n",(0,n.jsx)(s.h2,{id:i[4].id,children:i[4].value}),"\n",(0,n.jsxs)(s.p,{children:["This area has gone through several proposals. The broader\n",(0,n.jsx)(s.a,{href:"https://github.com/graphql/graphql-wg/blob/main/rfcs/SemanticNullability.md",children:"Semantic Nullability RFC"}),"\ncollects the problem history and solution matrix."]}),"\n",(0,n.jsx)(s.p,{children:"The latest proposals to watch are:"}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.a,{href:"https://github.com/graphql/graphql-spec/pull/1163",children:"Error behavior"})," defines\nthe client-selected ",(0,n.jsx)(s.code,{children:"onError"})," modes. GraphQL.js v17 makes one part of this\ncurrent proposal available experimentally through\n",(0,n.jsx)(s.code,{children:"@experimental_disableErrorPropagation"}),": the mode where errored positions\nresolve to ",(0,n.jsx)(s.code,{children:"null"})," without propagating through non-null parents."]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.a,{href:"https://github.com/graphql/graphql-spec/pull/1208",children:"Service capabilities"}),"\nis the capabilities work extracted from the error-behavior proposal. It\ndefines the introspection mechanism for advertising service-level features and\nconfiguration. It is related to error behavior because clients need to\ndiscover whether ",(0,n.jsx)(s.code,{children:"onError"})," is supported, which modes may be requested, and\nwhich behavior applies when no mode is requested."]}),"\n"]}),"\n",(0,n.jsx)(s.h2,{id:i[5].id,children:i[5].value}),"\n",(0,n.jsx)(s.p,{children:"The current GraphQL.js directive is intentionally experimental and uses an\nimplementation-prefixed name. Future standards work is expected to settle the\nrequest shape and discovery story separately:"}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsx)(s.li,{children:"The error-behavior proposal defines the execution modes."}),"\n",(0,n.jsxs)(s.li,{children:["Semantic nullability work defines how schemas and clients distinguish values\nthat are nullable in normal business logic from values that are only ",(0,n.jsx)(s.code,{children:"null"}),"\nbecause an execution error occurred."]}),"\n",(0,n.jsx)(s.li,{children:"The service-capabilities proposal defines how clients discover whether those\nmodes are supported and what the default behavior is."}),"\n"]}),"\n",(0,n.jsxs)(s.p,{children:["Until that settles, clients should only use\n",(0,n.jsx)(s.code,{children:"@experimental_disableErrorPropagation"})," with services that document support for\nit. When it is enabled, clients should treat ",(0,n.jsx)(s.code,{children:"null"})," at an errored path as an\nerror ",(0,n.jsx)(s.code,{children:"null"}),", not as a semantic ",(0,n.jsx)(s.code,{children:"null"}),"."]})]})},"/docs/disabling-error-propagation",{filePath:"pages/docs/disabling-error-propagation.mdx",timestamp:1781534656e3,pageMap:a.v,frontMatter:{title:"Disabling Error Propagation",sidebarTitle:"Disabling Error Propagation"},title:"Disabling Error Propagation"},"undefined"==typeof RemoteContent?h:RemoteContent.useTOC)}},function(e){e.O(0,[7812,3412,2888,9774,179],function(){return e(e.s=7750)}),_N_E=e.O()}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.