Describe the bug
After upgrading from graphql 2.5.11 to 2.5.20, we're seeing SystemStackError: stack level too deep in production. The error occurs during render(json: result) in our GraphQL controller. Reverting to 2.5.11 fixes it.
This appears related to the Dataloader/Lazy merge in 2.5.12 (#5422), similar to #5490 (unresolved Lazy objects leaking into the result hash), but in a different configuration — we use GraphQL::Dataloader (not NullDataloader) and don't use @defer.
Configuration
- graphql-ruby 2.5.20 (worked on 2.5.11)
- graphql-pro (1.29.10, unchanged)
- using
GraphQL::Dataloader::AsyncDataloader
- using
trace_with(GraphQL::Tracing::NewRelicTrace, set_transaction_name: true)
- No
@defer
- Rails 7.2, Ruby 3.4
Stack trace
The stack trace shows ActiveSupport::JSON hitting Object#as_json → instance_values.as_json → Hash#as_json in infinite recursion:
active_support/core_ext/object/json.rb:63:in `as_json` # Object#as_json → instance_values.as_json
active_support/core_ext/object/json.rb:188:in `block in Hash#as_json`
active_support/core_ext/object/json.rb:63:in `as_json`
active_support/core_ext/object/json.rb:188:in `block in Hash#as_json`
... (repeats until stack overflow)
The culprit is likely GraphqlController#execute, which calls render(json: result) where result is a GraphQL::Query::Result. The Result delegates as_json/to_json to @to_h, so the plain hash should serialize fine, but something appears to put a graphql internal object (with circular references) into the serialization path.
Repro
We cannot reproduce this locally as it only occurs in production with the real NewRelic agent active. This is consistent with #5490 where specific runtime conditions were required to trigger unresolved Lazy objects leaking into the result. For now, we've just rolled back to 2.5.11.
Describe the bug
After upgrading from graphql 2.5.11 to 2.5.20, we're seeing
SystemStackError: stack level too deepin production. The error occurs duringrender(json: result)in our GraphQL controller. Reverting to 2.5.11 fixes it.This appears related to the Dataloader/Lazy merge in 2.5.12 (#5422), similar to #5490 (unresolved Lazy objects leaking into the result hash), but in a different configuration — we use
GraphQL::Dataloader(not NullDataloader) and don't use@defer.Configuration
GraphQL::Dataloader::AsyncDataloadertrace_with(GraphQL::Tracing::NewRelicTrace, set_transaction_name: true)@deferStack trace
The stack trace shows
ActiveSupport::JSONhittingObject#as_json→instance_values.as_json→Hash#as_jsonin infinite recursion:The culprit is likely
GraphqlController#execute, which callsrender(json: result)whereresultis aGraphQL::Query::Result. TheResultdelegatesas_json/to_jsonto@to_h, so the plain hash should serialize fine, but something appears to put a graphql internal object (with circular references) into the serialization path.Repro
We cannot reproduce this locally as it only occurs in production with the real NewRelic agent active. This is consistent with #5490 where specific runtime conditions were required to trigger unresolved Lazy objects leaking into the result. For now, we've just rolled back to 2.5.11.