ChilliCream / ChilliCream/graphql-platform

`totalCount @include(if: $var)` on a connection is frozen by the first execution of the document

Open
#10,396 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

🌶️ hot chocolate
Dominant language
C#
Stars
5.8k
Forks
810
Avg merge
15h 39m
Merged PRs (30d)
98

Description

Product

Hot Chocolate

Version

16.6.6

Link to minimal reproduction

https://github.com/drebouta/graphql-platform-conditional-total-count-issue-repro

Steps to reproduce

dotnet run the app runs the same document twice, changing only the variable. It does that
twice over, each time with a fresh executor: run A starts with the variable false, run B starts with it true.

query Items($withTotalCount: Boolean!) {
  items(first: 10) {
    totalCount @include(if: $withTotalCount)
    nodes
  }
}
  1. Execute with { "withTotalCount": false }
  2. Execute the same document with { "withTotalCount": true }
  3. On a fresh executor, execute the same two requests in the opposite order
What is expected?

totalCount should return the value conditionaly upon requesting.

What is actually happening?

If the first execution @include evaluates to false, every execution afterwards fails with {"errors":[{"message":"Cannot return null for non-nullable field.","path":["items","totalCount"],"extensions":{"code":"HC0018"}}],"data":null}.
The document resolved @include to is reused for the lifetime of the compiled operation.
The resolver is handed ConnectionFlags = Nodes and PagingArguments.IncludeTotalCount = false,
so the page carries no count, while the response still shapes the totalCount: Int! field.

Run B - the same requests in the opposite order - works throughout, and there the count is
computed even for the request that did not ask for it. Only the order differs between the runs.

Relevant log output
dotnet run
A: first execution does not ask for totalCount
  withTotalCount: False
    resolver: Nodes | IncludeTotalCount: False
    {"data":{"items":{"nodes":["a","b","c"]}}}
  withTotalCount: True
    resolver: Nodes | IncludeTotalCount: False
    {"errors":[{"message":"Cannot return null for non-nullable field.","path":["items","totalCount"],"extensions":{"code":"HC0018"}}],"data":null}

B: first execution asks for totalCount
  withTotalCount: True
    resolver: Nodes, TotalCount | IncludeTotalCount: True
    {"data":{"items":{"totalCount":3,"nodes":["a","b","c"]}}}
  withTotalCount: False
    resolver: Nodes, TotalCount | IncludeTotalCount: True
    {"data":{"items":{"nodes":["a","b","c"]}}}
  withTotalCount: True
    resolver: Nodes, TotalCount | IncludeTotalCount: True
    {"data":{"items":{"totalCount":3,"nodes":["a","b","c"]}}}
Additional context
  • Reproduces on 16.6.6
  • The repro is a source-generated [QueryType] resolver with a PagingArguments parameter and
    ModifyPagingOptions(o => o.IncludeTotalCount = true), over an in-memory list; the
    ConnectionFlags parameter is there only to show the value the resolver receives.
  • Workaround: select totalCount unconditionally, or move the conditional variant into its own
    document.
  • Caught in production: Application restart together with first query having include: flase resulted in this issue, causing a major outage, since a very frequently used query was affected.

Contributor guide

Open the contributing guide

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

Start by running the linked minimal reproduction with its source-generated [QueryType] resolver, PagingArguments, and ModifyPagingOptions configuration. Trace how the compiled operation reuses the @include result and how ConnectionFlags and IncludeTotalCount are produced across repeated executions. Done means the same document honors the variable on every execution regardless of which value runs first, with regression coverage for both orders.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, graphql
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.