Fix projection drops member fields with field middleware - #10048
Merged
michaelstaib merged 6 commits intoJul 10, 2026
Merged
Conversation
This was referenced Jul 13, 2026
This was referenced Jul 20, 2026
chore(deps): Bump HotChocolate.Subscriptions.InMemory from 15.1.14 to 16.5.1
Kuestenlogik/Bowire#506
Merged
This was referenced Aug 1, 2026
This was referenced Aug 10, 2026
Open
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
SelectionExpressionBuilder.CollectSelectiononly projected fields with a pure resolver. Any middleware on a field removes its pure resolver, and one globalUseFieldremoves it from every field in the schema (ObjectField.IsPureContext).With a global middleware registered, every selected field was silently dropped from
QueryContext<T>andISelection.AsSelector<T>()selectors. The builder fell back to the id-only selector (root => new Entity { Id = root.Id }), the database only fetched the id column, and every selected non-nullable field failed at runtime withHC0018. Nothing at schema build time or in the logs pointed at the middleware.Fix
Purity decides how a field executes, not what data it needs. A member-bound resolver still reads the member when middleware wraps it, so the member still has to be projected.
CollectSelectionnow accepts a field when itsResolverMemberis declared on the parent runtime type, a base type, or an implemented interface. It no longer requires a pure resolver.The other guards are unchanged.
ResolveWithand extension resolvers stay excluded unless bound via[BindMember]. Method-inferred fields stay excluded by thePropertyInfocheck. Connection and collection segment fields stay excluded.One behavior change beyond the bug: member-declared fields with a custom
Resolve(...)delegate now project the member even when the delegate is not pure. This over-fetches at most one column and never under-fetches. Pure custom delegates already behaved this way.Test
GlobalFieldMiddlewareProjectionTestsregisters a pass-throughUseFieldon a schema with a plain entity and asserts the captured selector binds the selected member. Without the fix the selector only bindsIdand the request fails withHC0018.