Note: this involves GraphQL::Pro::Defer — happy to follow up through pro support channels if preferred.
Describe the bug
When a query uses @defer on a field and a sibling field exists at the same parent level (e.g. mcpServers alongside environment), the incremental delivery chunks contain the wrong path. The deferred data is delivered with the path of a sibling's node instead of the correct path, causing clients to apply the patch to the wrong location.
Versions
graphql version: 2.5.13
graphql-pro version: 1.29.13
rails: 8.0.4.1
GraphQL schema
class ApplicationSchema < GraphQL::Schema
use GraphQL::Pro::Defer
use GraphQL::Pro::FutureStream
end
# Controller
class GraphQLController < ApplicationController
include ActionController::Live
def execute
result = ApplicationSchema.execute(query, variables:, context:, operation_name:)
(deferred = result.context[:defer]) ? render_stream(deferred) : render(json: result)
end
def render_stream(deferred)
response.headers['Last-Modified'] = Time.now.httpdate
deferred.stream_http_multipart(response, incremental: true)
end
end
# Relevant types (simplified)
class OrganizationType < GraphQL::Schema::Object
field :environment, EnvironmentType, null: true
field :mcp_servers, MCPServerType.connection_type, null: false
end
class EnvironmentType < GraphQL::Schema::Object
field :connections, ConnectionType.connection_type, null: false
end
class ConnectionType < GraphQL::Schema::Object
field :connected, Boolean, null: false
end
class MCPServerType < GraphQL::Schema::Object
field :task_counts, TaskStatusCountsType, null: false
end
GraphQL query
query ConnectionsQuery($organizationId: ID!, $environmentSlug: String!) {
organization(id: $organizationId) {
id
environment(slug: $environmentSlug) {
id
connections(first: 10) {
nodes {
id
... @defer {
connected
}
}
}
}
mcpServers(first: 10) {
nodes {
id
taskCounts {
total
}
}
}
}
}
Steps to reproduce
- Set up a schema with
use GraphQL::Pro::Defer and a controller using stream_http_multipart(response, incremental: true)
- Define a query type with two sibling fields at the same level — one containing a
@defer fragment, the other with regular nested fields
- Execute the query and inspect the raw multipart HTTP response chunks
Expected behavior
Incremental chunks should carry the correct path pointing to the deferred selection set inside environment.connections.nodes:
{ "incremental": [{ "path": ["organization", "environment", "connections", "nodes", 0], "data": { "connected": true } }], "hasNext": true }
{ "incremental": [{ "path": ["organization", "environment", "connections", "nodes", 1], "data": { "connected": true } }], "hasNext": false }
Actual behavior
Both incremental chunks carry a path pointing to the sibling field (mcpServers) instead of environment.connections, and both incorrectly use index 0:
Chunk 1 (initial) — correct:
{
"hasNext": true,
"data": {
"organization": {
"environment": {
"connections": { "nodes": [{ "id": "aca6e0bf-..." }, { "id": "ed1b3e5e-..." }] }
},
"mcpServers": {
"nodes": [{ "id": "019c4c22-...", "taskCounts": { "total": 0 } }]
}
}
}
}
Chunk 2 — ❌ wrong path, wrong field, wrong index:
{ "incremental": [{ "path": ["organization", "mcpServers", "nodes", 0, "__typename"], "data": { "connected": true } }], "hasNext": true }
Chunk 3 — ❌ wrong path, wrong field, same index 0 for both items:
{ "incremental": [{ "path": ["organization", "mcpServers", "nodes", 0, "__typename"], "data": { "connected": true } }], "hasNext": false }
Two distinct issues in the paths:
- Wrong field: points to
mcpServers instead of environment.connections
- Wrong index: both chunks use index
0 instead of 0 and 1
Additional context
- Removing
taskCounts from mcpServers (or removing mcpServers entirely) produces correct paths — the bug only manifests when a sibling field with nested selections exists alongside the @defer-containing field at the same parent level.
- The query validates fine; the schema is otherwise functioning correctly.
- Workaround: remove
@defer from the query or split into two separate queries.
Note: this involves
GraphQL::Pro::Defer— happy to follow up through pro support channels if preferred.Describe the bug
When a query uses
@deferon a field and a sibling field exists at the same parent level (e.g.mcpServersalongsideenvironment), the incremental delivery chunks contain the wrongpath. The deferred data is delivered with the path of a sibling's node instead of the correct path, causing clients to apply the patch to the wrong location.Versions
graphqlversion: 2.5.13graphql-proversion: 1.29.13rails: 8.0.4.1GraphQL schema
GraphQL query
Steps to reproduce
use GraphQL::Pro::Deferand a controller usingstream_http_multipart(response, incremental: true)@deferfragment, the other with regular nested fieldsExpected behavior
Incremental chunks should carry the correct path pointing to the deferred selection set inside
environment.connections.nodes:{ "incremental": [{ "path": ["organization", "environment", "connections", "nodes", 0], "data": { "connected": true } }], "hasNext": true } { "incremental": [{ "path": ["organization", "environment", "connections", "nodes", 1], "data": { "connected": true } }], "hasNext": false }Actual behavior
Both incremental chunks carry a path pointing to the sibling field (
mcpServers) instead ofenvironment.connections, and both incorrectly use index0:Chunk 1 (initial) — correct:
{ "hasNext": true, "data": { "organization": { "environment": { "connections": { "nodes": [{ "id": "aca6e0bf-..." }, { "id": "ed1b3e5e-..." }] } }, "mcpServers": { "nodes": [{ "id": "019c4c22-...", "taskCounts": { "total": 0 } }] } } } }Chunk 2 — ❌ wrong path, wrong field, wrong index:
{ "incremental": [{ "path": ["organization", "mcpServers", "nodes", 0, "__typename"], "data": { "connected": true } }], "hasNext": true }Chunk 3 — ❌ wrong path, wrong field, same index
0for both items:{ "incremental": [{ "path": ["organization", "mcpServers", "nodes", 0, "__typename"], "data": { "connected": true } }], "hasNext": false }Two distinct issues in the paths:
mcpServersinstead ofenvironment.connections0instead of0and1Additional context
taskCountsfrommcpServers(or removingmcpServersentirely) produces correct paths — the bug only manifests when a sibling field with nested selections exists alongside the@defer-containing field at the same parent level.@deferfrom the query or split into two separate queries.