ChilliCream / ChilliCream/graphql-platform
Error when using $defer with incrementalSpec=v0.1
@michaelstaib is already working on this.
Since Sep 9, 2026.
- Dominant language
- C#
- Stars
- 5.8k
- Forks
- 810
- Avg merge
- 15h 39m
- Merged PRs (30d)
- 98
Description
Product
Hot Chocolate
Version
16.6.3
Link to minimal reproduction
https://github.com/srollinet/HotChocolate.IncrementalResultFormatAdapters.BugMinimalRepro
Steps to reproduce
- Start the server
- In Nitro, set header
Acceptwith valueapplication/json, multipart/mixed; incrementalSpec=v0.1 - Execute the following query:
query {
products {
nodes {
id
...ProductItemFragment @defer(label: "ProductsQuery$defer$productDetails")
}
}
}
fragment ProductItemFragment on Product {
productNumber
}
What is expected?
Query works, like in version 15
{
"data": {
"products": {
"nodes": [
{
"id": "1",
"productNumber": 1001
},
{
"id": "2",
"productNumber": 1002
},
{
"id": "3",
"productNumber": 1003
}
]
}
}
}
What is actually happening?
Sometimes, the result is empty, sometimes it's partial.
When receiving a partial result, patch1 is ok
{
"data": {
"products": {
"nodes": [
{
"id": "1"
},
{
"id": "2"
},
{
"id": "3"
}
]
}
}
}
Then patch2 fails
{
"name": "ServerParseError",
"statusCode": 200,
"statusText": "OK",
"bodyText": ""
}
Relevant log output
fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HNO9ONKK0TT6", Request id "0HNO9ONKK0TT6:00000002": An unhandled exception was thrown by the application.
System.InvalidOperationException: The requested operation requires an element of type 'Object', but the target element has type 'Array'.
at System.Text.Json.ThrowHelper.ThrowJsonElementWrongTypeException(JsonTokenType expectedType, JsonTokenType actualType)
at System.Text.Json.JsonDocument.TryGetNamedPropertyValue(Int32 index, ReadOnlySpan`1 propertyName, JsonElement& value)
at System.Text.Json.JsonElement.TryGetProperty(String propertyName, JsonElement& value)
at HotChocolate.Transport.Formatters.IncrementalRfc1ResultFormatAdapter.WriteMergedObject(JsonWriter writer, OperationResultFormatterContext context, Path path, JsonElement patchObject, DeferSelectionTree selection)
at HotChocolate.Transport.Formatters.IncrementalRfc1ResultFormatAdapter.TryCreateMergedData(OperationResultFormatterContext context, Path pendingPath, Path path, String label, JsonDocument patchDocument, ReadOnlyMemorySegment& mergedData, Path& mergedPath)
at HotChocolate.Transport.Formatters.IncrementalRfc1ResultFormatAdapter.WriteIncremental(JsonWriter writer, OperationResult result, JsonSerializerOptions options, OperationResultFormatterContext context)
at HotChocolate.Transport.Formatters.JsonResultFormatter.Format(OperationResult result, JsonWriter writer, Boolean useIncrementalRfc1, OperationResultFormatterContext& context)
at HotChocolate.Transport.Formatters.JsonResultFormatter.FormatInternal(OperationResult result, IBufferWriter`1 bufferWriter, Boolean useIncrementalRfc1, OperationResultFormatterContext& context)
at HotChocolate.Transport.Formatters.JsonResultFormatter.Format(OperationResult result, IBufferWriter`1 writer, Boolean useIncrementalRfc1, OperationResultFormatterContext& context)
at HotChocolate.Transport.Formatters.MultiPartResultFormatter.MessageHelper.WritePayload(IBufferWriter`1 writer, OperationResult result, JsonResultFormatter payloadFormatter, Boolean useIncrementalRfc1, OperationResultFormatterContext& context)
at HotChocolate.Transport.Formatters.MultiPartResultFormatter.FormatResponseStreamAsync(IResponseStream responseStream, PipeWriter writer, Boolean useIncrementalRfc1, CancellationToken ct)
at HotChocolate.Transport.Formatters.MultiPartResultFormatter.FormatResponseStreamAsync(IResponseStream responseStream, PipeWriter writer, Boolean useIncrementalRfc1, CancellationToken ct)
at HotChocolate.Transport.Formatters.MultiPartResultFormatter.FormatResponseStreamAsync(IResponseStream responseStream, PipeWriter writer, Boolean useIncrementalRfc1, CancellationToken ct)
at HotChocolate.AspNetCore.Formatters.DefaultHttpResponseFormatter.FormatInternalAsync(HttpResponse response, IExecutionResult result, Nullable`1 proposedStatusCode, FormatInfo format, AcceptMediaType acceptMediaType, CancellationToken cancellationToken)
at HotChocolate.AspNetCore.Formatters.DefaultHttpResponseFormatter.FormatAsync(HttpResponse response, IExecutionResult result, AcceptMediaType[] acceptMediaTypes, Nullable`1 proposedStatusCode, CancellationToken cancellationToken)
at HotChocolate.AspNetCore.HttpPostMiddlewareBase.HandleRequestAsync(HttpContext context, ExecutorSession session, CancellationToken ct)
at HotChocolate.AspNetCore.HttpPostMiddlewareBase.HandleRequestAsync(HttpContext context, ExecutorSession session, CancellationToken ct)
at HotChocolate.AspNetCore.HttpPostMiddlewareBase.InvokeAsync(HttpContext context)
at HotChocolate.AspNetCore.MiddlewareFactory.<>c__DisplayClass0_0.<<CreateCancellationMiddleware>b__1>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
Additional context
In my quick analysis, the problem happens in IncrementalRfc1ResultFormatAdapter.TryCreateMergedData https://github.com/ChilliCream/graphql-platform/blob/7ce54d90aaa724519fa10680408e788717154fab/src/HotChocolate/AspNetCore/src/Transport.Formatters/IncrementalResultFormatAdapters.cs#L213-L215
relativePath has value [0]. So, in WriteWrappedPatch, patch is wrapped in an array
And later, in WriteMergedObject, TryGetProperty throws because patchObject is an array
https://github.com/ChilliCream/graphql-platform/blob/7ce54d90aaa724519fa10680408e788717154fab/src/HotChocolate/AspNetCore/src/Transport.Formatters/IncrementalResultFormatAdapters.cs#L386-L390
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.