-
Notifications
You must be signed in to change notification settings - Fork 21
Description
There is a race condition in the header propagation system when executing multi-field GraphQL queries that span multiple subgraphs
in federation mode. The fromClientToSubgraphs
function receives subgraphName: undefined
during parallel execution, causing
authentication failures for queries with multiple top-level fields.
Steps to Reproduce
- Set up a federated GraphQL gateway with multiple subgraphs
- Configure header propagation using
fromClientToSubgraphs
- Execute a query with multiple top-level fields from different subgraphs:
query MultiFieldQuery {
userProfile { # From UserService subgraph
id
name
}
products { # From ProductService subgraph
id
title
}
}
- Observe that
subgraphName
parameter isundefined
in thefromClientToSubgraphs
function
Expected Behavior
The fromClientToSubgraphs
function should receive the correct subgraphName
for each subgraph request, allowing for
subgraph-specific header propagation.
Actual Behavior
- Single-field queries work correctly (subgraphName is properly set)
- Multi-field queries fail with
subgraphName: undefined
- Authentication headers are not properly propagated to subgraphs
Environment
- @graphql-hive/gateway: 1.15.4
- @graphql-mesh/fusion-runtime: 0.11.17
- Node.js: 18+
Root Cause Analysis
Based on source code analysis, this is a race condition between two hook execution flows:
- Header Propagation Flow
File: @graphql-hive/gateway-runtime/dist/index.js:1183
const subgraphName = executionRequest && subgraphNameByExecutionRequest.get(executionRequest);
- Subgraph Execution Flow
File: @graphql-mesh/fusion-runtime/dist/index.js:929
subgraphNameByExecutionRequest.set(executionRequest, subgraphName);
The Race Condition
- The
subgraphNameByExecutionRequest
WeakMap is populated inonSubgraphExecute()
- Header propagation tries to read from this WeakMap in
onFetch()
- During federation parallel execution, onFetch() is called BEFORE
onSubgraphExecute()
- This causes
subgraphNameByExecutionRequest.get()
to returnundefined
Why Single-field Queries Work
Single-field queries use sequential execution where timing is deterministic and onSubgraphExecute()
populates the WeakMap before
onFetch()
reads it.
Why Multi-field Queries Fail
Multi-field queries create parallel execution contexts where the timing becomes non-deterministic, leading to the race condition.
Workaround
const propagateHeadersFromClientToSubgraphs = ({ request, subgraphName }) => {
const headers = {};
// Handle race condition where subgraphName is undefined
if (!subgraphName) {
console.warn('[Race Condition] subgraphName undefined in multi-field query');
// Propagate all necessary headers as fallback
const fallbackHeaders = ['authorization', 'cookie', 'origin'];
fallbackHeaders.forEach((name) => {
const value = request.headers.get(name);
if (value) {
headers[name] = value;
}
});
return headers;
}
// Normal subgraph-specific header logic
// ... rest of implementation
};
Proposed Solution
The issue requires fixing the hook execution order to ensure that:
subgraphNameByExecutionRequest.set()
is called beforefromClientToSubgraphs()
- Or provide an alternative mechanism to reliably identify the target subgraph during header propagation
This appears to be a fundamental architectural issue requiring coordination between @graphql-hive/gateway-runtime
and
@graphql-mesh/fusion-runtime
.
Additional Context
This issue has been confirmed to persist across multiple versions (1.15.1 through 1.15.4) and affects any federation setup using
multi-field queries with header propagation.