Skip to content

A non-null field that resolves to null is left out of the response instead of raising a field error #578

Description

@lukemurray

Problem

When a field declared non-null resolves to null, EntityGraphQL leaves the field out of data and returns no error:

schema.Query().AddField("missing", db => db.Actors.FirstOrDefault(a => a.Id == 999), "x").IsNullable(false);
schema.Query().AddField("missingScalar", db => db.Actors.Where(a => a.Id == 999).Select(a => a.Name).FirstOrDefault(), "x").IsNullable(false);
Query Response today
{ missing { name } } { "data": {} }: no missing key, no error
{ missingScalar } { "data": {} }: no missingScalar key, no error

What the spec says

"Handling Field Errors" (§6.4.4, October 2021) and "Errors and Non-Null Fields":

  1. A non-null field that resolves to null raises a field error. The error goes in errors, with a path to the field.
  2. The null moves up to the parent field. If the parent is nullable, the parent becomes null. If the parent is also non-null, it keeps moving up.
  3. If every field from the root down to that field is non-null, data is null.
  4. A selected field is never just left out of the response. It appears as a value or as null.

So { missing { name } } should return:

{ "data": null, "errors": [{ "message": "...non-null field 'missing' returned null...", "path": ["missing"] }] }

For a nested field, for example a non-null director on a nullable movie, the result is "movie": null, plus the error with path ["movie", "director"].

Why 7.0

This changes responses clients get today: fields that are currently left out silently become errors, and their nullable parents become null. Clients that rely on the current shape (or on data being non-null) would see different results.

Notes

  • Checked for a non-null object field and a non-null scalar (above). Non-null list items ([T!]) not checked yet.
  • Found while reviewing Fix UseConnectionPaging on a nested EF collection #576. That PR stopped null-checking a connection's pageInfo, which is never null. It keeps the existing null check for every other object built in the query expression, so this issue's behaviour is unchanged there.

🤖 Generated with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    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