Skip to content

Handle SystemStackError in Execution::Next - #5705

Merged
rmosolgo merged 1 commit into
rmosolgo:masterfrom
ydah:handle-execution-stack-errors
Aug 27, 2026
Merged

Handle SystemStackError in Execution::Next#5705
rmosolgo merged 1 commit into
rmosolgo:masterfrom
ydah:handle-execution-stack-errors

Conversation

@ydah

@ydah ydah commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

This PR extends the execution-time SystemStackError handling added in #5683 to GraphQL::Execution::Next.

Previously, GraphQL::Execution::Next allowed a SystemStackError raised during execution to escape from GraphQL::Execution::Runner. This bypassed Schema#query_stack_error and returned an unhandled application error instead of GraphQL-Ruby's configured stack error response.

The runner now delegates execution-time stack errors to Schema#query_stack_error, matching the legacy interpreter behavior.

@rmosolgo

Copy link
Copy Markdown
Owner

I'm open to including this, but I'm curious, did you encounter it in normal use? Do you mind sharing a backtrace?

Execution::Next doesn't use recursive method calls like the old runtime did, so I'd be surprised if it raised these from its own execution.

If these come from application code, would rescue_from ... work to handle them?

@ydah

ydah commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

Thank you for asking. I encountered this during synthetic deep-query testing, not in normal application use.

I found that Execution::Next can still exhaust the stack when it uses NullDataloader. NullDataloader#append_job invokes each step synchronously, resulting in this recursive cycle:

GraphQL::Dataloader::NullDataloader#append_job
GraphQL::Execution::Runner#add_step
GraphQL::Execution::FieldResolveStep#enqueue_next_steps
GraphQL::Execution::FieldResolveStep#build_results
GraphQL::Execution::FieldResolveStep#execute_field
GraphQL::Execution::FieldResolveStep#build_arguments
GraphQL::Execution::FieldResolveStep#call
GraphQL::Dataloader::NullDataloader#append_job

On master, a schema using Execution::Next without max_depth raises an uncaught SystemStackError for a depth-800 query:

  • Query size: 8,018 bytes
  • Token count: 2,406
  • Validation: enabled
  • Application exception: none

The current generated schema is protected by max_depth(15) and uses GraphQL::Dataloader, so this does not reproduce with the generator defaults.

I also tested rescue_from(SystemStackError), but the handler is not called. SystemStackError inherits directly from Exception, while the field execution paths rescue StandardError before dispatching to rescue_from.

With this patch, the same query is passed to query_stack_error and returns:

{
  "errors" => [
    { "message" => "This query is too large to execute." }
  ]
}

@rmosolgo

Copy link
Copy Markdown
Owner

Ohhhh right -- I forgot that NullDataloader implements the queue as a stack. (Somewhere in my attempts to speed this up I tried rewriting it to use an actual queue, but without any Fibers. I wonder if that'd still be useful...)

Thanks for sharing this fix!

@rmosolgo rmosolgo added this to the 2.6.10 milestone Aug 27, 2026
@rmosolgo
rmosolgo merged commit 2c6ea04 into rmosolgo:master Aug 27, 2026
14 of 15 checks passed
@ydah
ydah deleted the handle-execution-stack-errors branch August 27, 2026 10:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants