Skip to content

router: grpc datasource stack overflows on recursive input objects during plan construction #2649

@fengyuwusong

Description

@fengyuwusong

Component(s)

router

Component version

github.com/wundergraph/cosmo/router local build based on 5b323e7090c6

wgc version

N/A (not involved in the reproduction; router loads execution config from file)

controlplane version

N/A / local execution config

router version

dev (local build based on 5b323e7090c6)

What happened?

If a gRPC datasource schema contains a recursive input object, the router crashes with fatal error: stack overflow while handling a GraphQL request.

This appears to happen during gRPC execution-plan construction, before any upstream/plugin call is executed.

If possible, please create a PR with a failing test to illustrate the issue clearly.
Otherwise, please attach a minimum reproduction through a GitHub repository that includes
essential information such as the relevant subgraph SDLs.
Please also make sure that the instructions for the reproduction are clear, tested, and fully accurate.

Description

A recursive input shape like this is enough to reproduce the problem:

scalar JSON

type Mutation {
  updateRule(input: UpdateRuleInput!): Rule!
}

type Rule {
  id: ID!
}

input UpdateRuleInput {
  id: ID!
  conditions: ConditionsInput
}

input ConditionsInput {
  and: [ConditionsInput!]
  or: [ConditionsInput!]
  key: String
  value: JSON
}

The router loads the execution config successfully and starts normally. But as soon as a request hits the recursive input type, the process exits with stack overflow.

The stack trace repeatedly alternates between:

  • grpc_datasource.(*rpcPlanVisitor).buildMessageField
  • grpc_datasource.(*rpcPlanVisitor).buildMessageFromNode

From local debugging, the recursion happens in:

  • pkg/engine/datasource/grpc_datasource/execution_plan_visitor.go:378
  • pkg/engine/datasource/grpc_datasource/execution_plan_visitor.go:417

There does not seem to be a recursion guard / visited-type cache for recursive input object expansion.

Steps to Reproduce

  1. Start the router with a local execution config that includes a gRPC datasource and a recursive input object like ConditionsInput above.
  2. Send a mutation such as:
{
  "query": "mutation UpdateRule($input: UpdateRuleInput!) { updateRule(input: $input) { id } }",
  "variables": {
    "input": {
      "id": "r1",
      "conditions": null
    }
  }
}
  1. Observe that the router process exits instead of returning an error or forwarding the request.

Expected Result

The router should support valid recursive input objects, or at minimum reject them gracefully during config/planning with a normal error.
It should not crash the process.

Actual Result

The router process exits with:

runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow

The stack repeatedly shows buildMessageField -> buildMessageFromNode -> buildMessageField -> ... in grpc_datasource/execution_plan_visitor.go.

Environment information

Environment

OS: macOS (Apple Silicon)
Package Manager: Go modules
Compiler(if manually compiled): go1.23.0

Router configuration

listen_addr: "127.0.0.1:18080"
dev_mode: true
plugins:
  enabled: false
execution_config:
  file:
    path: "./router.execution.config.json"
    watch: true

Router execution config

{
  "kind": "GRAPHQL",
  "customGraphql": {
    "grpc": {
      "mapping": {
        "service": "RpcService"
      },
      "protoSchema": "message UpdateRuleInput { string id = 1; ConditionsInput conditions = 2; } message ConditionsInput { repeated ConditionsInput and = 1; repeated ConditionsInput or = 2; google.protobuf.StringValue key = 3; google.protobuf.StringValue value = 4; }"
    }
  }
}

Log output

runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow
...
github.com/wundergraph/graphql-go-tools/v2/pkg/engine/datasource/grpc_datasource.(*rpcPlanVisitor).buildMessageField
...
github.com/wundergraph/graphql-go-tools/v2/pkg/engine/datasource/grpc_datasource.(*rpcPlanVisitor).buildMessageFromNode

Additional context

This was reproduced locally with plugins disabled, which suggests the crash happens before any plugin/upstream execution and is isolated to router plan construction for gRPC datasources.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinginternally-reviewedThe issue has been reviewed internally.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions