Skip to content

Comments

OneOf inhabitability#1211

Open
jbellenger wants to merge 1 commit intographql:mainfrom
jbellenger:jbellenger-oneof-inhabitability
Open

OneOf inhabitability#1211
jbellenger wants to merge 1 commit intographql:mainfrom
jbellenger:jbellenger-oneof-inhabitability

Conversation

@jbellenger
Copy link
Contributor

@jbellenger jbellenger commented Feb 17, 2026

OneOf types can form graphs for which finite values cannot be created.

The simplest example of this is a self-recursing OneOf type:

input A @oneOf { a:A }

While this is the simplest form of the issue, we can build more complex examples from trees where every type is a OneOf:

input A @oneOf { b:B c:C }
input B @oneOf { c:C a:A }
input C @oneOf { a:A b:B }

These kinds of types are considered valid on two fronts today:

  1. They are valid as OneOf types because all field types are nullable and there are no default values
  2. They are valid as a circular input object because there are no unbreakable chains of non-null non-list fields

While this follows the letter of the Circular References part of the spec, it violates the spirit of the spec in that there is no way to create a legal value for these types.

I propose that in keeping with the spirit of the Circular References section, that these topologies be declared invalid. I took a stab at clarifying the spec around these kinds of types. With a provisional thumbs-up I'll plan on adding validation to graphql-js and graphql-java.

@netlify
Copy link

netlify bot commented Feb 17, 2026

Deploy Preview for graphql-spec-draft ready!

Name Link
🔨 Latest commit 1e86f0a
🔍 Latest deploy log https://app.netlify.com/projects/graphql-spec-draft/deploys/6993b34efad165000846d8f4
😎 Deploy Preview https://deploy-preview-1211--graphql-spec-draft.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@jbellenger jbellenger marked this pull request as ready for review February 17, 2026 00:17
@benjie benjie added the 💭 Strawman (RFC 0) RFC Stage 0 (See CONTRIBUTING.md) label Feb 17, 2026
@benjie
Copy link
Member

benjie commented Feb 17, 2026

Excellent catch! I think we can and should fast track this. Once you have the GraphQL.js implementation in place either add it to the next GraphQL WG agenda or let me know if you’d rather I represent it on your behalf.

Copy link
Member

@benjie benjie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's change the named type to an assertion for clarity

Comment on lines +1813 to +1819
- Let {namedFieldType} be the underlying named type of {fieldType}.
- If {namedFieldType} is not an Input Object type:
- Return {true}.
- If {namedFieldType} is not a _OneOf Input Object_:
- Return {true}.
- If {OneOfInputObjectCanBeProvidedAFiniteValue(namedFieldType, nextVisited)}:
- Return {true}.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Let {namedFieldType} be the underlying named type of {fieldType}.
- If {namedFieldType} is not an Input Object type:
- Return {true}.
- If {namedFieldType} is not a _OneOf Input Object_:
- Return {true}.
- If {OneOfInputObjectCanBeProvidedAFiniteValue(namedFieldType, nextVisited)}:
- Return {true}.
- Assert: {fieldType} is a named type.
- If {fieldType} is not an Input Object type:
- Return {true}.
- If {fieldType} is not a _OneOf Input Object_ type:
- Return {true}.
- If {OneOfInputObjectCanBeProvidedAFiniteValue(fieldType, nextVisited)}:
- Return {true}.

viaductbot pushed a commit to airbnb/viaduct that referenced this pull request Feb 17, 2026
viaduct.arbitrary.graphql is a suite of generators used to property test Viaduct and other internal airbnb systems. The generators in this package use a model for GraphQL values, which can be applied to GraphQL objects that require them. Examples of this include the default values for a graphql argument definition, the arguments/variables used in a GraphQL document, or the result of executing a selection set.

This value model has evolved over time -- the initial `RawValue` family of types has been gradually replaced with an `IR.Value` model. Currently, both models exist in the code base and are used for slightly different jobs.

This PR completely removes the `RawValue` model and updates all systems to use `IR.Value`. Along the way it also updates most components to operate on a ViaductSchema rather than graphql-java's GraphQLSchema.

**Better Edgecase Coverage**
Before this change, the schema generator would assign default values and applied directives as it generated each type.
This created complexity in other parts of the system (eg value generators had to know how to not generate a value for a type that hadn't been defined yet), and made it impossible for the system to generate some kinds of edge cases.

This PR changes this behavior to insert default values and applied directives as additional passes, after all types have been generated. This simplifies value generation and allows for more kinds of edge cases to be generated.

This ability to generate more edge cases has surfaced some novel issues, such as this potential spec issue with OneOf types: graphql/graphql-spec#1211

Github-Change-Id: 998226
GitOrigin-RevId: 6ae10823b358faf51f883d593d33d6767933ee8b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💭 Strawman (RFC 0) RFC Stage 0 (See CONTRIBUTING.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants