Title: Improper handling of cyclical directive defs (spec issue) · Issue #4201 · graphql-java/graphql-java · GitHub
Open Graph Title: Improper handling of cyclical directive defs (spec issue) · Issue #4201 · graphql-java/graphql-java
X Title: Improper handling of cyclical directive defs (spec issue) · Issue #4201 · graphql-java/graphql-java
Description: Describe the bug The spec prohibits the definitions of directives to reference each other directly or indirectly via applied directives. GraphQL Java (25) correctly detects the direct case, but overflows the stack during validation for t...
Open Graph Description: Describe the bug The spec prohibits the definitions of directives to reference each other directly or indirectly via applied directives. GraphQL Java (25) correctly detects the direct case, but ove...
X Description: Describe the bug The spec prohibits the definitions of directives to reference each other directly or indirectly via applied directives. GraphQL Java (25) correctly detects the direct case, but ove...
Opengraph URL: https://github.com/graphql-java/graphql-java/issues/4201
X: @github
Domain: patch-diff.githubusercontent.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Improper handling of cyclical directive defs (spec issue)","articleBody":"**Describe the bug**\n\nThe spec prohibits the definitions of directives to reference each other directly or indirectly via applied directives. GraphQL Java (25) correctly detects the direct case, but overflows the stack during validation for the indirect case.\n\n[Diagnostics link](https://chatgpt.com/s/dr_6959bbdfea208191b610320a44cd9e84)\n\n**To Reproduce**\n```\nimport graphql.schema.idl.SchemaParser;\nimport graphql.schema.idl.TypeDefinitionRegistry;\nimport graphql.schema.idl.UnExecutableSchemaGenerator;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\n/**\n * Reproduction test for graphql-java circular directive dependency bug.\n *\n * When directives mutually reference each other via applied directives on their\n * arguments, UnExecutableSchemaGenerator.makeUnExecutableSchema() throws\n * StackOverflowError instead of detecting the cycle and reporting a proper error.\n *\n * NOTE: graphql-java correctly detects direct self-reference (A -\u003e A) and throws\n * SchemaProblem, but fails to detect indirect cycles (A -\u003e B -\u003e A) or longer\n * cycles (A -\u003e B -\u003e C -\u003e A), resulting in StackOverflowError.\n *\n * Dependencies: graphql-java, JUnit 5\n */\npublic class CircularDirectiveStackOverflowTest {\n\n @Test\n void selfReferencingDirectiveCorrectlyThrowsSchemaProblem() {\n // A directive that references itself via applied directive on its argument\n // graphql-java correctly detects this direct self-reference\n String sdl = \"\"\"\n directive @recursive(depth: Int @recursive(depth: 0)) on FIELD_DEFINITION | ARGUMENT_DEFINITION\n\n type Query { field: String @recursive(depth: 5) }\n \"\"\";\n\n TypeDefinitionRegistry registry = new SchemaParser().parse(sdl);\n\n // This correctly throws SchemaProblem (not a bug)\n assertThrows(graphql.schema.idl.errors.SchemaProblem.class, () -\u003e {\n UnExecutableSchemaGenerator.makeUnExecutableSchema(registry);\n });\n }\n\n @Test\n void mutualDirectiveReferenceCausesStackOverflowError() {\n // Two directives that reference each other via applied directives on arguments\n // This is an indirect cycle: @foo -\u003e @bar -\u003e @foo\n String sdl = \"\"\"\n directive @foo(x: Int @bar(y: 1)) on FIELD_DEFINITION | ARGUMENT_DEFINITION\n directive @bar(y: Int @foo(x: 2)) on FIELD_DEFINITION | ARGUMENT_DEFINITION\n\n type Query { field: String @foo(x: 10) @bar(y: 20) }\n \"\"\";\n\n TypeDefinitionRegistry registry = new SchemaParser().parse(sdl);\n\n // BUG: This throws StackOverflowError instead of a proper validation error\n assertThrows(StackOverflowError.class, () -\u003e {\n UnExecutableSchemaGenerator.makeUnExecutableSchema(registry);\n });\n }\n\n @Test\n void threeWayCircularDirectiveReferenceCausesStackOverflowError() {\n // Three directives forming a cycle: @dirA -\u003e @dirB -\u003e @dirC -\u003e @dirA\n String sdl = \"\"\"\n directive @dirA(x: Int @dirB(y: 1)) on FIELD_DEFINITION | ARGUMENT_DEFINITION\n directive @dirB(y: Int @dirC(z: 2)) on FIELD_DEFINITION | ARGUMENT_DEFINITION\n directive @dirC(z: Int @dirA(x: 3)) on FIELD_DEFINITION | ARGUMENT_DEFINITION\n\n type Query { field: String @dirA(x: 10) @dirB(y: 20) @dirC(z: 30) }\n \"\"\";\n\n TypeDefinitionRegistry registry = new SchemaParser().parse(sdl);\n\n // BUG: This throws StackOverflowError instead of a proper validation error\n assertThrows(StackOverflowError.class, () -\u003e {\n UnExecutableSchemaGenerator.makeUnExecutableSchema(registry);\n });\n }\n}\n```\n","author":{"url":"https://github.com/rstata","@type":"Person","name":"rstata"},"datePublished":"2026-01-04T01:03:09.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/4201/graphql-java/issues/4201"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:ec2f73a3-8ceb-ac34-7bfe-dfb4a949933a |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | DD78:3CE303:CE68AF:1240BBE:696F4BC1 |
| html-safe-nonce | 2995f873f474d2dd2cebbee810198f9853828989c0878c53d62898b3793b61da |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJERDc4OjNDRTMwMzpDRTY4QUY6MTI0MEJCRTo2OTZGNEJDMSIsInZpc2l0b3JfaWQiOiI1NzUxMzMzNzM1MTAxMzIwMTI5IiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | 38d412c979a731dc01afee7433d1d5615bb36068721f7ea96215bb90037ea566 |
| hovercard-subject-tag | issue:3778645604 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/graphql-java/graphql-java/4201/issue_layout |
| twitter:image | https://opengraph.githubassets.com/af2fb55051ecf89487e47801b9b2883d968213bb3710dd8c7767c7946d594e58/graphql-java/graphql-java/issues/4201 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/af2fb55051ecf89487e47801b9b2883d968213bb3710dd8c7767c7946d594e58/graphql-java/graphql-java/issues/4201 |
| og:image:alt | Describe the bug The spec prohibits the definitions of directives to reference each other directly or indirectly via applied directives. GraphQL Java (25) correctly detects the direct case, but ove... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | rstata |
| hostname | github.com |
| expected-hostname | github.com |
| None | 49bb2ee76ae1b4ec758faefafda636ff20b05a9708bb290d28422cdf542ae979 |
| turbo-cache-control | no-preview |
| go-import | github.com/graphql-java/graphql-java git https://github.com/graphql-java/graphql-java.git |
| octolytics-dimension-user_id | 14289921 |
| octolytics-dimension-user_login | graphql-java |
| octolytics-dimension-repository_id | 38602457 |
| octolytics-dimension-repository_nwo | graphql-java/graphql-java |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 38602457 |
| octolytics-dimension-repository_network_root_nwo | graphql-java/graphql-java |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 036f37fe552777ac9c6ee661957f947285aab936 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width