Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Order of Inline Fragments Causes Missing Data #8063

Open
samyonr opened this issue Feb 23, 2025 · 0 comments
Open

Order of Inline Fragments Causes Missing Data #8063

samyonr opened this issue Feb 23, 2025 · 0 comments

Comments

@samyonr
Copy link

samyonr commented Feb 23, 2025

Product

Strawberry Shake

Version

15.0.3

Link to minimal reproduction

https://github.com/samyonr/StrawberryShake.OrderOfInlineFragment.Bug

Steps to reproduce

  1. Clone or download the attached repo.
  2. cd StrawberryShake.OrderOfInlineFragment.Bug.Tests
  3. dotnet test
  4. Observe that FragmentOrderBug_PartialFragment_Failing test fails, while the others pass.

Run the tests and note that:

  • FragmentOrderBug_FullFragment_Working() → PASS. Because the Bird fragment is requested for both people and shelters.
  • FragmentOrderBug_FullFragment_ExplicitQuery_Working() → PASS. We manually post the full query to /graphql and the JSON contains Bird data.
  • FragmentOrderBug_PartialFragment_Failing() → FAIL. Strawberry Shake’s typed result incorrectly omits Bird fields or treats it as null. The server response definitely includes them.
  • FragmentOrderBug_PartialFragment_ExplicitQuery_Working() → PASS. Manually posting the partial query returns Bird data.

What is expected?

Expected
When we run NotWorkingQuery, the first shelter’s pet (a Bird) should appear with wingSpan=42. The server’s raw JSON response includes it, so the Strawberry Shake client should include it as well.

Actual
.Data is null, and .Error is Value cannot be null.

What is actually happening?

Actual
.Data is null, and .Error is Value cannot be null.

For the auto-generated schema below (generated with dotnet graphql init http://localhost:5058/graphql -n StrawBerryShakeClient):

schema {
  query: Query
}

interface IPet {
  id: Int!
}

type Query {
  people: [Person!]!
  shelters: [Shelter!]!
}

type Dog implements IPet {
  id: Int!
  breed: String!
}

type Cat implements IPet {
  id: Int!
  furColor: String!
}

type Bird implements IPet {
  id: Int!
  wingSpan: Int!
}

type Shelter {
  id: Int!
  location: String!
  pet: IPet
}

type Person {
  id: Int!
  name: String!
  pet: IPet
}

We are running two queries:

query WorkingQuery {
    people {
        id
        name
        pet {
            id
            __typename
            ... on Bird {
                wingSpan
            }
            ... on Cat {
                furColor
            }
            ... on Dog {
                breed
            }
        }
    }
    shelters {
        id
        location
        pet {
            id
            __typename
            ... on Bird {
                wingSpan
            }
            ... on Cat {
                furColor
            }
            ... on Dog {
                breed
            }
        }
    }
}

and:

query NotWorkingQuery {
    people {
        id
        name
        pet {
            id
            __typename
            ... on Cat {
                furColor
            }
            ... on Dog {
                breed
            }
        }
    }
    shelters {
        id
        location
        pet {
            id
            __typename
            ... on Bird {
                wingSpan
            }
            ... on Cat {
                furColor
            }
            ... on Dog {
                breed
            }
        }
    }
}

The second query doesn't work for the Strawberry Shake client, but it does work when we send the query explicitly, without a client.

  • The problem seems to arise specifically when the first object (people) omits one of the possible implementing types (e.g. Bird), but the second object (shelters) references it. If the second object requests the missing type, Strawberry Shake’s client fails.
  • If you reverse the order of fields in the query or ensure all fragments are used in both cases, it works fine.
  • This bug has been observed in various versions of Strawberry Shake (e.g. ~13.x – 15.x).

Relevant log output

[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.0.2+dd36e86129 (64-bit .NET 9.0.2)
[xUnit.net 00:00:03.09]   Discovering: StrawberryShake.OrderOfInlineFragment.Bug.Tests
[xUnit.net 00:00:03.29]   Discovered:  StrawberryShake.OrderOfInlineFragment.Bug.Tests
[xUnit.net 00:00:03.54]   Starting:    StrawberryShake.OrderOfInlineFragment.Bug.Tests
[xUnit.net 00:00:08.79]     StrawberryShake.OrderOfInlineFragment.Bug.Tests.Reproduction.FragmentOrderBug_PartialFragment_Failing [FAIL]
[xUnit.net 00:00:08.79]       Assert.NotNull() Failure: Value is null
[xUnit.net 00:00:08.79]       Stack Trace:
[xUnit.net 00:00:08.79]         StrawberryShake.OrderOfInlineFragment.Bug\StrawberryShake.OrderOfInlineFragment.Bug.Tests\Reproduction.cs(73,0): at StrawberryShake.OrderOfInlineFragment.Bug.Tests.Reproduction.FragmentOrderBug_PartialFragment_Failing()
[xUnit.net 00:00:08.79]         --- End of stack trace from previous location ---
[xUnit.net 00:00:08.88]   Finished:    StrawberryShake.OrderOfInlineFragment.Bug.Tests
  StrawberryShake.OrderOfInlineFragment.Bug.Tests test failed with 1 error(s) (10.7s)
    StrawberryShake.OrderOfInlineFragment.Bug\StrawberryShake.OrderOfInlineFragment.Bug.Tests\Reproduction.cs(73): error TESTERROR:
      StrawberryShake.OrderOfInlineFragment.Bug.Tests.Reproduction.FragmentOrderBug_PartialFragment_Failing (5s 174ms): Error Message: Assert.NotNull() Failure: Value is null
      Stack Trace:
         at StrawberryShake.OrderOfInlineFragment.Bug.Tests.Reproduction.FragmentOrderBug_PartialFragment_Failing() in StrawberryShake.OrderOfInlineFragment.Bug\StrawberryShake.O      rderOfInlineFragment.Bug.Tests\Reproduction.cs:line 73
      --- End of stack trace from previous location ---

Test summary: total: 4, failed: 1, succeeded: 3, skipped: 0, duration: 10.6s
Build failed with 1 error(s) in 15.8s

---

and when debugging:
System.ArgumentNullException: Value cannot be null.
   at StrawberryShake.OrderOfInlineFragment.Bug.Tests.State.NotWorkingQueryResultFactory.MapINotWorkingQuery_Shelters_Pet(IIPetData data) in StrawberryShake.OrderOfInlineFragment.Bug\StrawberryShake.OrderOfInlineFragment.Bug.Tests\obj\Debug\net9.0\berry\StrawBerryShakeClient.Client.cs:line 2630
   at StrawberryShake.OrderOfInlineFragment.Bug.Tests.State.NotWorkingQueryResultFactory.MapNonNullableINotWorkingQuery_Shelters(ShelterData data) in StrawberryShake.OrderOfInlineFragment.Bug\StrawberryShake.OrderOfInlineFragment.Bug.Tests\obj\Debug\net9.0\berry\StrawBerryShakeClient.Client.cs:line 2585
   at StrawberryShake.OrderOfInlineFragment.Bug.Tests.State.NotWorkingQueryResultFactory.MapNonNullableINotWorkingQuery_SheltersNonNullableArray(IReadOnlyList`1 list) in trawberryShake.OrderOfInlineFragment.Bug\StrawberryShake.OrderOfInlineFragment.Bug.Tests\obj\Debug\net9.0\berry\StrawBerryShakeClient.Client.cs:line 2574
   at StrawberryShake.OrderOfInlineFragment.Bug.Tests.State.NotWorkingQueryResultFactory.Create(IOperationResultDataInfo dataInfo, IEntityStoreSnapshot snapshot) in StrawberryShake.OrderOfInlineFragment.Bug\StrawberryShake.OrderOfInlineFragment.Bug.Tests\obj\Debug\net9.0\berry\StrawBerryShakeClient.Client.cs:line 2484
   at StrawberryShake.OperationResultBuilder`1.Build(Response`1 response)

Additional context

Strawberry Shake Bug: Order of Inline Fragments Causes Missing Data

A bug in Strawberry Shake causes data for an interface‐implementing type to be missing when:

  • The GraphQL query contains multiple inline fragments (... on SomeType) for an interface,
  • One part of the query omits a particular implementing type, but another part includes it,
  • The part that includes the omitted type appears later in the query.

As a result, Strawberry Shake’s type handling sometimes never returns the omitted type’s fields in the final result, even though the server response does include them.

In the minimal reproduction:

  • The people field queries only Dog/Cat, omitting Bird,
  • The shelters field in the same query requests Dog, Cat, and Bird,
  • The first shelter actually has a Bird, but Strawberry Shake doesn't return it.

Repository Structure

We have two projects:

  1. StrawberryShake.OrderOfInlineFragment.Bug.Web

    • An ASP.NET Core app with Hot Chocolate hosting a small GraphQL schema (an interface IPet with multiple implementations).
    • Program.cs sets up the GraphQL server at /graphql.
    • GraphQL.cs has the domain model (Person, Shelter, Dog, Cat, Bird, etc.).
  2. StrawberryShake.OrderOfInlineFragment.Bug.Tests

    • Contains the tests (xUnit) and the Strawberry Shake queries (WorkingQuery.graphql, NotWorkingQuery.graphql).
    • Uses WebApplicationFactory<Program> to spin up the Web project in‐memory.
    • Has four tests:
      1. Full fragment via Strawberry Shake client (works),
      2. Full fragment via raw HTTP query (works),
      3. Partial fragment via Strawberry Shake client (fails—the bug),
      4. Partial fragment via raw HTTP query (works).

Three of these tests pass, but the partial‐fragment test with the Strawberry Shake client fails. The server’s JSON response does have the Bird data, so it’s not a server bug. The client just doesn’t map it due to the inline‐fragment coverage issue.

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

No branches or pull requests

2 participants