You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Empty union base definitions rejected before extensions are merged (spec violation) #4200
(UnionTypeDefinition : Description? union Name Directives[Const]? UnionMemberTypes?)
makes UnionMemberTypes optional. SchemaParser correctly parses this SDL and TypeDefinitionRegistry correctly shows the union extensions. However, SchemaGenerator.makeExecutableSchema() fails validation with:
SchemaProblem{errors=[Union type 'Pet' must include one or more member types.]}
Root cause is that the validation checks the base definition before merging extension members (which isn't done for other types like interfaces). For deeper dive on root cause see this link.
(GraphQL Java 25.0)
To Reproduce
import graphql.schema.idl.SchemaParser
import graphql.schema.idl.UnExecutableSchemaGenerator
import org.junit.jupiter.api.Test
/**
* Demonstrates a graphql-java bug: empty union base definitions with members
* added via extensions are rejected, even though the GraphQL spec allows this.
*
* The spec grammar (UnionTypeDefinition : Description? union Name Directives[Const]? UnionMemberTypes?)
* makes UnionMemberTypes optional. SchemaParser correctly parses this SDL and
* TypeDefinitionRegistry correctly shows the union extensions. However,
* SchemaGenerator.makeExecutableSchema() fails validation with:
*
* SchemaProblem{errors=[Union type 'Pet' must include one or more member types.]}
*
* The validation checks the base definition before merging extension members.
*/
class UnionTest {
@Test
fun `test empty union base`() {
val sdl = """
type Cat { meow: String }
type Dog { bark: String }
union Pet
extend union Pet = Cat | Dog
type Query { pet: Pet }
""".trimIndent()
val registry = SchemaParser().parse(sdl)
println("=== Registry parsed successfully ===")
println("Types: ${registry.types().keys}")
println("Union extensions: ${registry.unionTypeExtensions()}")
try {
val schema = UnExecutableSchemaGenerator.makeUnExecutableSchema(registry)
println("=== Schema built successfully ===")
} catch (e: Exception) {
println("=== Exception ===")
println("Class: ${e.javaClass.name}")
println("Message: ${e.message}")
e.printStackTrace()
throw e
}
}
}
Hello, this issue has been inactive for 60 days, so we're marking it as stale. If you would like to continue this discussion, please comment within the next 30 days or we'll close the issue.
Activity
rstata commentedon Jan 4, 2026
Java rewrite:
github-actions commentedon Mar 5, 2026
Hello, this issue has been inactive for 60 days, so we're marking it as stale. If you would like to continue this discussion, please comment within the next 30 days or we'll close the issue.
Fix #4200: Allow empty union base definitions when extensions add mem…
Fix #4200: Allow empty union definitions when extensions provide members
github-actions commentedon Apr 4, 2026
Hello, as this issue has been inactive for 90 days, we're closing the issue. If you would like to resume the discussion, please create a new issue.
Fix #4364 and #4200: nullable type bound and empty union extension su…
andimarek commentedon May 20, 2026
This is fixed in #4388