Skip to content

fix(schema): don't collapse allOf-intersected string with date-time to empty#3026

Open
schani wants to merge 4 commits into
masterfrom
agent/fix-issue-1770
Open

fix(schema): don't collapse allOf-intersected string with date-time to empty#3026
schani wants to merge 4 commits into
masterfrom
agent/fix-issue-1770

Conversation

@schani

@schani schani commented Jul 20, 2026

Copy link
Copy Markdown
Member

Bug

Generating C# (or any language) from GitHub's webhook JSON Schema
(@octokit/webhooks-schemas@4.2.1/schema.json) fails with:

Error: Trying to make an empty union - do you have an impossible type in your schema?.

No output is produced at all.

Root cause

allOf in JSON Schema is resolved as a type intersection in
packages/quicktype-core/src/rewrites/ResolveIntersections.ts
(IntersectionAccumulator.updatePrimitiveTypes). That method intersects the
set of primitive kinds seen across the allOf members using
isPrimitiveTypeKind, which only covers null | bool | integer | double | string — it does not include "transformed string" kinds such as
date-time, date, time, uuid, etc.

So when one allOf branch is a plain {"type": "string"} (or a union like
{"type": ["string", "null"]}) and another branch is
{"type": "string", "format": "date-time"}, the date-time branch
contributes nothing to the primitive-kind intersection (it isn't a
"primitive kind"), and the running intersection collapses to the empty set
— even though a date-time string is a specialization of string, not a
disjoint/conflicting type. With no primitive kind, no array kind, and no
object kind left, IntersectionUnionBuilder.buildUnion builds a union with
zero members, which trips the IRNoEmptyUnions assertion.

This exact pattern occurs repeatedly in the real webhook schema, e.g. a
committer.date property is defined as {"type": "string", "format": "date-time"} in one definition and re-stated as {"type": "string"} in an
allOf sibling elsewhere — a common pattern when schema authors combine a
$ref via allOf with an object that repeats a property with a looser
constraint.

Fix

In IntersectionAccumulator.updatePrimitiveTypes, when one side of the
intersection has (plain) "string" and the other has one or more
transformed string kinds, narrow the result to those transformed kinds
instead of dropping them — mirroring the existing haveNumber special case
just above it, which already reconciles integer vs double the same way.
getMemberKinds() was also updated so the plain string's accumulated type
attributes are preserved on the narrowed transformed-string kind. Two
different transformed kinds (e.g. date-time vs uuid) still correctly
conflict and produce an empty intersection, since that is a genuine
contradiction.

Test coverage

Added a JSON Schema fixture that reproduces the bug: an object type whose
date property is {"type": "string", "format": "date-time"}, intersected
via allOf with a sibling schema that restates the same property as plain
{"type": "string"}:

  • test/inputs/schema/transformed-string-intersection.schema
  • test/inputs/schema/transformed-string-intersection.1.json

This fixture is picked up automatically by every language's schema-<lang>
fixture (per test/fixtures.ts conventions), so it will be exercised by CI
across all supported target languages.

Verification

  • Confirmed the bug on unfixed master: node dist/index.js --lang cs --src-lang schema schema.json against the real
    @octokit/webhooks-schemas@4.2.1 schema failed with the exact reported
    "empty union" error; a minimized reproduction of the same shape failed the
    same way.
  • After the fix: the real webhook schema and the minimized repro both
    generate C# successfully (exit 0), with the affected property emitted as
    DateTimeOffset.
  • npx vitest run test/unit: 163/163 tests pass.
  • npm run build passes cleanly.
  • QUICKTEST=true FIXTURE=schema-csharp script/test test/inputs/schema/transformed-string-intersection.schema could not be
    run in this sandbox (no dotnet toolchain available to compile/run the
    generated C#), so full fixture round-trip verification for C# is left to
    CI; the fixture itself is a normal, automatically-registered
    test/inputs/schema/*.schema + .1.json pair following the same pattern
    as the existing intersection*.schema fixtures.

Fixes #1770.

🤖 Generated with Claude Code

schani and others added 3 commits July 20, 2026 17:57
…tc to empty (#1770)

Co-Authored-By: gpt-5.6-sol via pi <noreply@openai.com>
…chema (#3026)

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown

Generated-output differences

35 files differ — 0 modified, 35 new, 0 deleted
2534 changed lines — +2534 / −0

Open the generated-output report →

@github-actions

Copy link
Copy Markdown

Generated-output differences

36 files differ — 0 modified, 36 new, 0 deleted
2601 changed lines — +2601 / −0

Open the generated-output report →

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.

Unable to generate C# types for GitHub's webhook schema

1 participant