Skip to content

Conversation

@amondnet
Copy link
Contributor

@amondnet amondnet commented Nov 28, 2025

Pull request checklist

  • Please read our contributor guide
  • Consider creating a discussion on the discussion forum first
  • Make sure the PR doesn't introduce backward compatibility issues
  • Make sure to have sufficient test cases

Pull Request type

  • Bugfix
  • Feature
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • Other (please describe):

Changes in this PR

This PR fixes a NullPointerException that occurs when using Apollo Federation subscription callbacks with ApolloFederatedTracingHeaderForwarder enabled.

Issue #2077

Problem

When using Apollo Router with Netflix DGS Framework for GraphQL subscriptions with HTTP callbacks, enabling ApolloFederatedTracingHeaderForwarder causes:

java.lang.NullPointerException: get(...) must not be null
at com.netflix.graphql.dgs.context.DgsContext$Companion.from(DgsContext.kt:46)
at com.netflix.graphql.dgs.context.GraphQLContextContributorInstrumentation.createState(GraphQLContextContributorInstrumentation.kt:42)

Root Cause

The issue is caused by an interceptor execution order problem:

  • CallbackWebGraphQLInterceptor runs at LOWEST_PRECEDENCE (designed to run LAST)
  • GraphQLContextContributorInstrumentation.createState() is called BEFORE DgsWebFluxGraphQLInterceptor
  • Attempts to call DgsContext.from(graphQLContext) before DgsContext has been added to GraphQL context

Solution

Add null-safe access to DgsContext for subscription callback scenarios:

  1. Add DgsContext.fromOrNull() method - A safe accessor that returns null instead of throwing NPE when DgsContext is not present
  2. Update GraphQLContextContributorInstrumentation - Use null-safe access to handle cases where DgsContext may not be initialized yet

Files Changed

  • graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/context/DgsContext.kt

    • Add fromOrNull() companion method with KDoc documentation
  • graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/context/GraphQLContextContributorInstrumentation.kt

    • Use null-safe DgsContext.fromOrNull() instead of DgsContext.from()
  • New test files:

    • graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/context/DgsContextTest.kt
    • graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/context/GraphQLContextContributorInstrumentationTest.kt

Backwards Compatibility

This is a backwards-compatible bug fix:

  • DgsContext.from() still throws NPE when context missing (existing behavior preserved)
  • DgsContext.fromOrNull() is a new method - no impact on existing code
  • Context contributors must handle null requestData gracefully, but implementations already use nullable types

Alternatives considered

  1. Interceptor Order Coordination - Force DgsWebFluxGraphQLInterceptor to run before subscription callback setup by setting @Order(Ordered.HIGHEST_PRECEDENCE). This was rejected as it may conflict with Apollo's design of running callback interceptor last.

  2. Lazy Instrumentation Initialization - Defer GraphQLContextContributorInstrumentation logic to a later phase. This was rejected as it requires larger refactoring and may break existing behavior.

  3. Try-catch wrapper - Wrap the DgsContext.from() call in try-catch. This was rejected in favor of explicit null-safe API which is cleaner and more idiomatic.

The chosen solution (null-safe accessor) is minimal, backwards compatible, and explicit about the constraint.

Add null-safe access to DgsContext for subscription callback scenarios
where DgsContext may not be initialized yet due to interceptor execution
order.

Changes:
- Add DgsContext.fromOrNull() method for safe context retrieval
- Update GraphQLContextContributorInstrumentation to use null-safe access
- Add unit tests for DgsContext and GraphQLContextContributorInstrumentation

This fixes Netflix#2077 where using ApolloFederatedTracingHeaderForwarder with
subscription callbacks caused NullPointerException because createState()
was called before DgsWebFluxGraphQLInterceptor initialized DgsContext.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant