Skip to content

Race condition in header propagation for multi-field federation queries causes subgraphName to be undefined #1311

@rowanparker

Description

@rowanparker

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

  1. Set up a federated GraphQL gateway with multiple subgraphs
  2. Configure header propagation using fromClientToSubgraphs
  3. 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
    }
  }
  1. Observe that subgraphName parameter is undefined in the fromClientToSubgraphs 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:

  1. Header Propagation Flow

File: @graphql-hive/gateway-runtime/dist/index.js:1183
const subgraphName = executionRequest && subgraphNameByExecutionRequest.get(executionRequest);

  1. Subgraph Execution Flow

File: @graphql-mesh/fusion-runtime/dist/index.js:929
subgraphNameByExecutionRequest.set(executionRequest, subgraphName);

The Race Condition

  1. The subgraphNameByExecutionRequest WeakMap is populated in onSubgraphExecute()
  2. Header propagation tries to read from this WeakMap in onFetch()
  3. During federation parallel execution, onFetch() is called BEFORE onSubgraphExecute()
  4. This causes subgraphNameByExecutionRequest.get() to return undefined

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:

  1. subgraphNameByExecutionRequest.set() is called before fromClientToSubgraphs()
  2. 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.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions