Skip to content

[Fusion] Fix requirements anchored below the lookup target returning null - #10704

Merged
michaelstaib merged 1 commit into
mainfrom
mst/fusion-requirement-path
Oct 26, 2026
Merged

michaelstaib merged 1 commit into
mainfrom
mst/fusion-requirement-path

Conversation

@michaelstaib

Copy link
Copy Markdown
Member

When a field with @require is on a type that has no lookup in its source schema, the planner fetches it through the lookup of the nearest parent that has one. The plan then says that the requirement data sits below that parent, at the object that holds the field. The gateway ignored this and looked for the data on the parent itself. It found nothing, so it never sent the request, and the field came back as null without an error.

The gateway now follows the requirement's path from the parent down to the object and reads the data there. If that object is null, a type condition does not match, or a list is in the way, the gateway skips that item instead of sending a request with missing data. The plans themselves do not change.

Example

Schema a:

type Query {
  products: [Product!]!
}

type Product {
  id: Int! @shareable
  details: Details @shareable
}

type Details {
  weight: Int!
}

Schema b, where Details has no lookup:

type Query {
  productById(id: Int!): Product @lookup @internal
}

type Product @key(fields: "id") {
  id: Int! @shareable
  details: Details @shareable
}

type Details {
  shippingEstimate(weight: Int! @require(field: "weight")): Int!
}
{
  products {
    id
    details {
      shippingEstimate
    }
  }
}

Before, b was never called and every shippingEstimate came back as null, although the field is non-null. Now b receives each product's weight and returns the estimates.

…null

The planner inlines a requiring field into a lookup step even when the field
sits below the step target, for example when the requiring type has no lookup
of its own. The requirement then carries the path of the selection set that
holds the field, while the executor mapped its selection map from the target
element. The map found nothing, the step was never sent and the field returned
null without an error.

FetchResultStore now resolves each requirement from the element at its path
relative to the target, as OperationRequirement documents and as the Apollo
representation builder and the deferred requirement import already do. A
target is skipped when it has no object at that path: the anchor or an object
on the way to it is null, a type condition does not match, or a list is on the
way, since one variable cannot carry a value per list item. The fast paths
still handle requirements anchored at the target.
@github-actions

Copy link
Copy Markdown
Contributor

Patch coverage

100.0% of changed lines covered (79/79)

File Covered Changed Patch %
…/src/Fusion.Execution/Execution/Results/FetchResultStore.cs 79 79 100.0% 🟢

Project coverage: 59.4% (317161/533756 lines)

@michaelstaib
michaelstaib merged commit dbcda62 into main Oct 26, 2026
158 checks passed
@michaelstaib
michaelstaib deleted the mst/fusion-requirement-path branch October 26, 2026 23:31
This was referenced Oct 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant