graphql-dotnet / graphql-dotnet/graphql-dotnet

Node `.Parent` skips containers of arrays

Open
#4,495 1 comment 0 reactions 0 assignees Claimed by @Shane32 View on GitHub
bug
Dominant language
C#
Stars
6k
Forks
945
Avg merge
3d 13h
Merged PRs (30d)
14

Description

## Description

When traversing the `.Parent` property tree of an `IResolveFieldContext`, the parent of a `ListGraphType` will be omitted from the tree. This is easier to demonstrate than explain, please see [this gist](https://gist.github.com/dLopreiato/be949e52fd0aacf93d86ec29b80b5aa6).

### Steps to reproduce

1. Set up a graph schema that contains some `ListGraphType`.
2. In a resolver of `T`, execute `context.Parent`.

Expect the parent of `ListGraphType`. Get the `ListGraphType`.

The above linked gist demonstrates the scenario by recursively walking terminal nodes and creating a string of parent names walked. This demonstration is intended to make it easy to see, but the actual problem is with `.Parent`, not just `.ParentType`. (A `parentTree` property has also been provided that puts together a list of CLR types of the models or `.Source` types.)

This gist can also be used to reproduce this issue by putting a breakpoint in the resolver for `parentTree` and manually walking up the `.Parent` tree. None of the types in this walk will be `PingMulti`, when at least one should.

### Expected result

`.Parent` should return the container type of `ListGraphType`, not the `ListGraphType`. As demonstrated in the gist, something like this:

```json
{
"data": {
"multi": {
// Omitted for brevity
"list": [
{
"parentTypeTree": "Ping - PingMulti - Query"
},
// ...
]
}
}
}
```

### Actual result

`.Parent` actually returns the `ListGraphType`, then *that parent* returns a skipped parent (in the gist, this is `Query`), which means the container of `ListGraphType` (in this gist, this is `PingMulti`) is entirely skipped.

```json
{
"data": {
"multi": {
// Omitted for brevity
"list": [
{
"parentTypeTree": "Ping - %null - Query"
},
// ...
]
}
}
}
```

### Environment

Only tested on .NET 10, Ubuntu 24.04.4 LTS, x64 Architecture. I am able to repro on GraphQL lib versions 7.0.0, 8.8.4, and 8.8.5. (Source does not compile for versions earlier than 7.0.0.)

### Impact

Some of my graph types can only ever exist as a child to a specific entity (as exemplified in the gist as `PingType` for the child and `PingMultiType` for the parent). I never let any user query for `PingType` unless they are querying through `PingMultiType`. When resolving a `PingType` property, I want to access the model of `PingMultiType` for contextual information, so I walk the parent tree until `.Source` returns the model of the type I'm looking for (`PingMultiType.Model`). If `PingType` is stored as an array on `PingMultiType`, I will never find the model I'm looking for. For all other cases, this mechanism works as expected.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by running the linked gist with a schema containing ListGraphType and inspect the resolver that walks IResolveFieldContext.Parent. Trace the Parent chain from a resolver for T and compare it with the expected parentTypeTree. Done means the container type between the list element and the query is preserved in the Parent tree, including its Source model.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
api
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
58/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.