spring-projects / spring-projects/spring-graphql

Single-entity @EntityMapping should resolve an empty Mono to a null _Entity (per Federation spec) instead of raising a per-entity error

Open
#1,516 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: waiting-for-triage
Dominant language
Java
Stars
1.6k
Forks
336
PR merge metrics
No merged PRs in 30d

Description

What

For a single-entity federated reference resolver:

@EntityMapping
public Mono<Book> book(@Argument String id) {
    return repository.findById(id);   // Mono.empty() when not found
}

an empty Mono (the idiomatic reactive "not found") is turned into a hard per-entity GraphQL error — "Entity fetcher returned null or completed empty" — rather than resolving that entity to null.

Source: EntitiesDataFetcher.invokeEntityMethod:

return handlerMethod.getEntity(environment, representation)
    .switchIfEmpty(Mono.error(new RepresentationNotResolvedException(representation, handlerMethod)))
    .onErrorResume((ex) -> resolveException(ex, environment, handlerMethod, index));

Why this is arguably wrong

  1. The Apollo Federation subgraph spec defines _entities(representations: [_Any!]!): [_Entity]! — the list is non-null but its elements are nullable, and the spec states: "Entries in the list can be null if no entity exists for a provided representation." So resolving an unresolvable representation to null is spec-compliant; erroring is stricter than the spec.

  2. Mono.empty() is the natural reactive signal for "absent"; converting it to an error is surprising.

  3. Inconsistency within the framework: the batch form (List<T> / Mono<List<T>>) already lets a null list entry become a null entity with no error — EntitiesDataFetcher.applyResults does entities.set(index, null) for a non-ErrorContainer (null) result. So the framework can already emit spec-legal nulls; only the ergonomic single-Mono form cannot.

Impact

A subgraph that references another subgraph's entity by a key that may legitimately not resolve (e.g. content deleted after the reference was recorded) cannot return a spec-compliant null from the single-entity form. It must either pre-validate every key or switch to the batch form purely to obtain null tolerance. At the gateway the per-entity error is surfaced to clients (e.g. graphql-request throws on any GraphQL error, failing the whole operation).

Proposed change

Let the single-entity @EntityMapping (Mono<T>) resolve an empty Mono to a null entity — matching the nullable _Entity element and the batch form — or provide an opt-in for that behaviour.

Repro

An @EntityMapping Mono<T> returning Mono.empty() yields the error "Entity fetcher returned null or completed empty" instead of a null entity.

Environment

  • Spring for GraphQL (Spring Boot 4.0.x)
  • Apollo Federation v2 (FederationSchemaFactory)

References

  • EntitiesDataFetcher.invokeEntityMethod (single) vs applyResults (batch) — spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntitiesDataFetcher.java
  • Apollo Federation subgraph spec, _entities field

Disclaimer

This summary was created with the help of AI during a debugging session on why optional entities throw errors

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Read spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntitiesDataFetcher.java, starting with invokeEntityMethod and comparing its single-entity handling with applyResults. Reproduce an @EntityMapping method returning Mono.empty(), then verify that the single-entity form produces a null entity without the per-entity error while existing batch behavior remains unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
graphql, java, spring
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.