Debugging Missing @key Fields in Apollo Federation v2
Missing @key fields in a federated graph trigger immediate composition failures or silent runtime entity resolution errors. This guide provides a systematic diagnostic workflow for identifying, isolating, and resolving @key misconfigurations in Apollo Federation v2.
Federation v2 @key Directive Requirements
In Federation v2, the @key directive explicitly defines the primary identifier for an entity, enabling the router to construct cross-subgraph representations. Unlike v1, v2 enforces strict schema validation: every entity must declare at least one @key field. The router uses these fields to route partial queries to the correct subgraph. If a field is omitted from the SDL or lacks the directive, composition fails deterministically. For a complete breakdown of entity mapping mechanics, review the Subgraph Implementation & Entity Resolution architecture guide.
Diagnosing Composition Failures via Rover CLI
Always begin troubleshooting by capturing the exact composition error. Run the following command against your local schema files:
rover supergraph compose --config supergraph.yaml
A missing or malformed @key directive produces a standardized validation payload:
[ERROR] Entity type 'Product' is missing a @key directive. Ensure all entities declare at least one @key field for cross-subgraph resolution.
If the directive exists but references an undefined field, the output shifts to:
[ERROR] Field 'productId' is not defined in the entity type 'Product'.
These logs isolate the failure to a specific subgraph, entity type, and missing field. Cross-reference the output with your local SDL to verify directive placement and field declarations.
Step-by-Step Resolution Workflow
Follow this diagnostic path to resolve composition failures:
- Audit the Failing Subgraph SDL: Locate the entity type referenced in the Rover error.
- Verify Directive Syntax: Ensure
@keyis attached directly to the type definition. Use the minimal viable configuration:
type Product @key(fields: "id") {
id: ID!
name: String
price: Float
}
Note: In v2, extend type is used for entities defined in other subgraphs, while type Product @key(fields: "id") is used in the owning subgraph.
3. Validate Field Existence & Type Consistency: The field referenced in @key(fields: "...") must be explicitly declared in the type block. Crucially, scalar types must match exactly across all subgraphs. A mismatch (e.g., ID! in Subgraph A vs String! in Subgraph B) will fail composition.
4. Re-run Composition: Execute rover supergraph compose to validate the schema.
5. Test Entity Resolution: Once composition succeeds, validate runtime behavior using Apollo Sandbox.
Runtime Validation & Reference Resolver Implementation
Successful composition does not guarantee functional entity resolution. You must implement a __resolveReference resolver to fetch the full entity payload when the router requests it.
Minimal Viable Resolver (Node.js/TypeScript):
const resolvers = {
Product: {
__resolveReference: async (reference, context) => {
// 'reference' contains the exact @key fields requested by the router
const { id } = reference;
return await db.products.findById(id);
}
}
};
Ensure the resolver extracts the @key field from the incoming reference object and queries your data source. For advanced resolver patterns and performance tuning, consult Implementing Entity Resolvers with @key Directives.
Verification Query & Expected Response: Execute a cross-subgraph query to trigger entity resolution:
query {
topProducts(first: 2) {
id
name
reviews {
score
comment
}
}
}
Router Trace Expectation:
- Subgraph A returns
[{ id: "1", name: "Laptop" }] - Router extracts
id: "1"and routes to Subgraph B - Subgraph B
__resolveReferencereceives{ __typename: "Product", id: "1" } - Subgraph B returns
{ id: "1", reviews: [...] } - Router merges payloads and returns the final response.
Monitor Apollo Router logs for __resolveReference execution times. High latency or null returns indicate resolver misconfiguration or missing @key field alignment.
Common Pitfalls & Resolutions
| Mistake | Root Cause | Resolution |
|---|---|---|
Omitting @key on the base subgraph |
Assuming the router infers identifiers automatically. | Explicitly declare @key(fields: "fieldName") on the originating entity type. |
Incompatible scalar types for @key fields |
Defining String in one subgraph and ID in another. |
Standardize the scalar across all referencing subgraphs (prefer ID!). |
@key field omitted from type definition |
Field used in directive but missing from the SDL block. | Ensure the field is explicitly defined with matching casing and type in the type block. |
Incorrect @external usage |
Marking the @key field as @external in the owning subgraph. |
Only use @external in extending subgraphs. The owning subgraph must define the field natively. |
FAQ
Why does Apollo Federation v2 require explicit @key fields for entities?
Federation v2 enforces explicit @key declarations to guarantee deterministic entity resolution across distributed services. This eliminates ambiguity during schema composition and ensures the router can reliably construct entity representations for cross-subgraph queries.
Can I use multiple fields in a single @key directive?
Yes. Federation v2 supports composite keys using the syntax @key(fields: "id version"). The router will use the combined values to uniquely identify the entity across subgraphs.
How do I verify that my reference resolver is correctly using the @key field?
Use the Apollo Sandbox or GraphQL Playground to execute a query that spans multiple subgraphs. Enable router-level logging (--log-level=debug) to trace __resolveReference execution and confirm that the resolver receives the exact @key field payload and returns the expected entity data.
Next Steps
- Commit the corrected SDL and re-run
rover subgraph publish. - Enable distributed tracing in your Apollo Router to monitor entity resolution latency.
- Implement automated schema checks in your CI/CD pipeline using
rover subgraph checkto catch@keyviolations before deployment.