Skip to content

fix(rust): don't panic when there are no top-level types#3019

Merged
schani merged 1 commit into
masterfrom
agent/fix-issue-1629
Jul 21, 2026
Merged

fix(rust): don't panic when there are no top-level types#3019
schani merged 1 commit into
masterfrom
agent/fix-issue-1629

Conversation

@schani

@schani schani commented Jul 20, 2026

Copy link
Copy Markdown
Member

What was broken

Generating Rust from a TypeScript source that has no #TopLevel-marked
interface (the common case — #TopLevel is an internal quicktype
convention, not something users write) crashed with:

Error: Internal error: Defined value expected, but got undefined.

Repro (from the issue, using VS Code's debugProtocol.d.ts):

node dist/index.js --lang rs --derive-debug --density dense --visibility private \
  --out debugProtocolTypes.rs --src-lang typescript --src debugProtocol.d.ts

C# generation from the same input succeeds, confirming this was a
Rust-renderer-specific bug rather than a TypeScript-input or CLI issue (some
issue commenters chased an unrelated -- argument-parsing red herring).

Root cause

When the TypeScript-to-JSON-Schema conversion finds no #TopLevel marker, it
falls back to uris: ["#/definitions/"], which does not name any specific
top-level type — the renderer's this.topLevels map ends up legitimately
empty even though the type graph itself is non-empty. RustRenderer's
emitLeadingComments() unconditionally did:

const topLevelName = defined(mapFirst(this.topLevels)).getCombinedName();

defined() panics whenever its argument is undefined, so an empty
topLevels map crashed the whole run. Other renderers (e.g. C#'s
emitDefaultLeadingComments) don't assume a top level exists for their
default leading comment, so only Rust was affected.

Fix

In packages/quicktype-core/src/language/Rust/RustRenderer.ts,
emitLeadingComments() now checks whether a top level exists and simply
skips the top-level-specific example comment when it doesn't, instead of
panicking:

const topLevel = mapFirst(this.topLevels);
if (topLevel === undefined) return;

const topLevelName = topLevel.getCombinedName();

This is a narrowly scoped change — no other renderer or shared code paths
were touched.

Test coverage

This condition (empty topLevels with a non-empty type graph) isn't
reachable through the JSON/JSON-Schema fixture harness, since fixture
schemas always assign a concrete top-level name. Per repo convention this
makes a test/unit/ test the right coverage, following the same pattern as
test/unit/typescript-input.test.ts and
test/unit/kotlin-klaxon-empty-object-map.test.ts.

Added test/unit/rust-empty-top-levels.test.ts, which drives quicktype()
directly with a JSONSchemaInput built the same way
quicktype-typescript-input builds one when no #TopLevel marker is
present (uris: ["#/definitions/"]), asserting:

  • Rust renders without throwing when the schema's definitions produce no
    top-level type at all.
  • Rust still renders named types correctly when a top level is present
    (regression guard).

Verification

  • npm run build passes.
  • npx vitest run test/unit/rust-empty-top-levels.test.ts test/unit/typescript-input.test.ts — all pass.
  • Re-ran the exact repro from the issue against the built dist/index.js
    with the real VS Code debugProtocol.d.ts: previously crashed with the
    "Defined value expected" panic, now exits 0 and writes valid Rust source.
  • QUICKTEST=true FIXTURE=rust script/test (full Rust fixture suite, using
    the local rustc/cargo toolchain) — run locally to confirm no
    regressions; CI will also validate this on the PR.

Fixes #1629

🤖 Generated with Claude Code

Rust's emitLeadingComments() assumed at least one top-level type exists to
name in its example-usage comment, panicking with "Defined value expected,
but got undefined" whenever this.topLevels was empty. This is legitimate,
reachable state: TypeScript sources without a #TopLevel marker (the common
case) fall back to uris: ["#/definitions/"], producing a non-empty type
graph with zero named top levels. Now the renderer simply skips the
top-level-specific example comment when there is nothing to name.

Co-Authored-By: gpt-5.6-sol via pi <noreply@openai.com>
@schani
schani merged commit 48becca into master Jul 21, 2026
28 checks passed
@schani
schani deleted the agent/fix-issue-1629 branch July 21, 2026 13:34
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.

Error: Internal error: Defined value expected, but got undefined.

1 participant