Subgraph Error Inclusion
Configure the router to propagate subgraph errors to clients
By default, a GraphOS Router or Apollo Router Core redacts the details of subgraph errors in responses to clients. The router instead returns a default error with the following message:
1Subgraph errors redacted
This redaction prevents potential leaks of sensitive information to the client. Using the include_subgraph_errors
plugin, you can configure the router to propagate subgraph errors to clients instead. You can do this for all subgraphs, or on a per-subgraph basis.
Configuration
To configure subgraph error inclusion, add the include_subgraph_errors
plugin to your YAML config file, like so:
1# Option 1: Simple boolean toggle (default is false)
2include_subgraph_errors:
3 all: true # Propagate errors (message + extensions) from all subgraphs
4 subgraphs:
5 products: false # Override: Do not propagate errors from the 'products' subgraph (redact fully)
Any configuration under the subgraphs
key takes precedence over the all
configuration for that specific subgraph. In the example above, subgraph errors are included from all subgraphs except the products
subgraph, which will have its errors fully redacted.
If all
is a boolean (true
or false
), then any configuration under subgraphs
must also be a boolean.
1# Option 2: Fine-grained control using objects
2include_subgraph_errors:
3 all: # Default configuration for all subgraphs
4 redact_message: true # Redact error messages globally
5 allow_extensions_keys: # Allow only specific extension keys globally
6 - code
7 - trace_id
8 subgraphs:
9 # Subgraph 'products': Override global settings
10 products:
11 redact_message: false # Keep original error messages for 'products'
12 allow_extensions_keys: # Extend global allow list for 'products'
13 - reason # Allows 'code', 'trace_id' (from global) and 'reason'
14 exclude_global_keys: # Exclude 'trace_id' from the inherited global list
15 - trace_id # Allows 'code' (global) and 'reason' (subgraph), but not 'trace_id'
16
17 # Subgraph 'inventory': Override global allow list with a deny list
18 inventory:
19 deny_extensions_keys: # Deny specific keys for 'inventory' (overrides global allow list)
20 - internal_debug_info
21 # Allows 'code', 'trace_id' (from global) but denies 'internal_debug_info'
22
23 # Subgraph 'reviews': Use only common options, inheriting global allow/deny behavior
24 reviews:
25 redact_message: false # Override only message redaction, inherits global allow list
26 exclude_global_keys: # Inherits global allow list, but excludes 'code'
27 - code # Allows 'trace_id' but not 'code'
28
29 # Subgraph 'accounts': Fully redact errors, overriding global object config
30 accounts: false
deny_extensions_keys
approach carries security risks because it follows a blocklist pattern—any sensitive information not explicitly included in the deny list might be exposed to clients if not covered by other rules (like a global allow_extensions_keys
).For better security, we recommend either fully redacting subgraph errors (by setting the subgraph to false
) or using the allow_extensions_keys
approach (either globally or per-subgraph) to explicitly specify which error extension fields can be exposed to clients.
Configuration Schema
The top-level include_subgraph_errors
key accepts an object with the following keys:
Key | Type | Description | Default |
---|---|---|---|
all | boolean | ErrorMode Object | Configuration applied to all subgraphs unless overridden. | false |
subgraphs | map<string, boolean | ErrorMode Object> | Per-subgraph overrides for the all configuration. The key is the subgraph name. | {} |
ErrorMode Object
This object provides fine-grained control over error propagation.
Key | Type | Description | Required |
---|---|---|---|
redact_message | boolean | If true , replaces the original error message with Subgraph errors redacted . If false , keeps the original message. | Optional |
allow_extensions_keys | [string] | Propagates only the specified keys in the extensions object. Cannot be used with deny_extensions_keys in the same object. If omitted, inherits global behavior. | Optional |
deny_extensions_keys | [string] | Redacts the specified keys from the extensions object. Cannot be used with allow_extensions_keys in the same object. If omitted, inherits global behavior. | Optional |
exclude_global_keys | [string] | When inheriting a global allow_extensions_keys or deny_extensions_keys list, these keys are removed from the inherited list before applying subgraph-specific rules. | Optional |
Key Behaviors & Precedence
Subgraph Specificity: Configuration under
subgraphs.<subgraph_name>
always overrides theall
configuration for that specific subgraph.Boolean Override: If
subgraphs.<subgraph_name>
is set totrue
orfalse
, it completely overrides anyall
object configuration.true
: Include the error, keep the original message, include all extensions (exceptservice
if explicitly denied later, though unlikely withtrue
).false
: Redact the error message and remove all extensions.
Global Boolean Restriction: If
all
is set totrue
orfalse
, then all entries undersubgraphs
must also betrue
orfalse
. Object configurations are not allowed for subgraphs in this case.Allow vs. Deny: Within a single configuration object (either
all
or a specific subgraph),allow_extensions_keys
anddeny_extensions_keys
are mutually exclusive.Inheritance & Overrides (Object Config):
If a subgraph config is an object, it inherits the behavior (
allow
ordeny
list,redact_message
) from the globalall
object config by default.redact_message
in the subgraph object overrides the globalredact_message
.allow_extensions_keys
in the subgraph object:Overrides a global
deny_extensions_keys
list.Extends a global
allow_extensions_keys
list (after applyingexclude_global_keys
).
deny_extensions_keys
in the subgraph object:Overrides a global
allow_extensions_keys
list.Extends a global
deny_extensions_keys
list (after applyingexclude_global_keys
).
exclude_global_keys
removes keys from the inherited global list before the subgraph'sallow
ordeny
list is applied or extended.
service
Extension: Theservice
extension (containing the subgraph name) is added by default if errors are included for a subgraph, unless it's explicitly removed by anallow_extensions_keys
list (that doesn't include"service"
) or adeny_extensions_keys
list (that includes"service"
).
Sending errors to GraphOS
Reporting subgraph errors to GraphOS is configured separately and is not affected by client-facing error inclusion settings. See the GraphOS reporting docs.
Logging GraphQL request errors
To log the GraphQL error responses (i.e., messages returned in the GraphQL errors
array) from the router, see the logging configuration documentation.
Exposing subgraph name via service
extension
If errors are included for a particular subgraph (i.e., not fully redacted by setting its config to false
), the router attempts to add the subgraph's name to the error's extensions
object under the key service
.
This service
extension key is treated like any other extension key and is subject to the allow_extensions_keys
and deny_extensions_keys
rules.
If using
allow_extensions_keys
, you must include"service"
in the list if you want it to be propagated.If using
deny_extensions_keys
, including"service"
will prevent it from being propagated.If no allow/deny lists apply (e.g.,
all: true
),"service"
will be included by default.
Example:
Assume include_subgraph_errors.all
is configured as:
1all:
2 redact_message: false
3 allow_extensions_keys:
4 - code # Allows only 'code', implicitly denying 'service'
If the products
subgraph returns an error like {"message": "Invalid ID", "extensions": {"code": "BAD_USER_INPUT"}}
, the final error sent to the client will be:
1{
2 "message": "Invalid ID",
3 "path": [...],
4 "extensions": {
5 "code": "BAD_USER_INPUT"
6 // "service": "products" is NOT included because it wasn't in allow_extensions_keys
7 }
8}
If the configuration was instead:
1all:
2 redact_message: false
3 allow_extensions_keys:
4 - code
5 - service # Explicitly allow 'service'
The final error would be:
1{
2 "data": null,
3 "errors": [
4 {
5 "message": "Invalid product ID",
6 "path": [],
7 "extensions": {
8 "service": "products",
9 }
10 }
11 ]
12}