Skip to content

[BUG]: Rust renderer crashes with "Internal error: ." when JSON Schema contains non-string const values #2856

@Vricken

Description

@Vricken

Issue Type

This is an issue during code generation - the Rust renderer fails when processing valid JSON Schema input containing const fields with non-string values (particularly booleans).

Context (Environment, Version, Language)

Input Format: JSON Schema (Draft 7)

Output Language: Rust

CLI, npm, or app.quicktype.io: CLI (also affects npm package quicktype-core)

Version: 23.2.6

Description

When generating Rust code from a JSON Schema that contains a const field with a boolean value, quicktype crashes with an unhelpful error message: Error: Internal error: .

This prevents code generation for schemas commonly produced by tools like zod-to-json-schema when using z.literal(true) or z.literal(false). The issue affects real-world usage where schemas need to define constant boolean values, particularly for discriminated unions or configuration objects with fixed boolean properties.

Root cause: The Rust renderer's rustType() method can return a raw boolean literal (e.g., true) instead of a valid source object. This literal value reaches serializeToStringArray() in Source.js, where it fails the switch (source.kind) check (since booleans have no .kind property), resulting in assertNever(source) being called.

Input Data

{
  "type": "object",
  "properties": {
    "is_enabled": {
      "type": "boolean",
      "const": true,
      "default": true
    }
  },
  "required": ["is_enabled"]
}

Real-world context: This pattern is generated by zod-to-json-schema from:

z.object({
  isEnabled: z.literal(true)
})

Expected Behaviour / Output

Quicktype should successfully generate Rust code, treating the const as a validation constraint. Expected output:

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
pub struct Test {
    pub is_enabled: bool,
}

Or at minimum, provide a clear error message explaining that const with non-string values is unsupported.

Current Behaviour / Output

Quicktype crashes with:

Error: Internal error: .

No additional context or stack trace is provided, making it difficult to diagnose the issue.

Debug information (when instrumenting assertNever):

assertNever called with: true
at serializeToStringArray (/node_modules/quicktype-core/dist/Source.js:182:50)

Steps to Reproduce

  1. Create a JSON Schema file with a boolean const value:
echo '{
  "type": "object",
  "properties": {
    "is_enabled": {
      "type": "boolean",
      "const": true
    }
  },
  "required": ["is_enabled"]
}' > schema.json
  1. Run quicktype to generate Rust code:
quicktype --lang rust --src-lang schema --top-level Test schema.json
  1. Observe the error:
Error: Internal error: .
  1. The same error occurs with the npm package:
const { quicktype, InputData, JSONSchemaInput, FetchingJSONSchemaStore } = require('quicktype-core');
// ... (attempting to generate from the schema above)
// Results in: Error: Internal error: .

Possible Solution

Option 1: Preprocess to Remove const (Workaround - User Side)

Users can strip const values before passing to quicktype:

function normalizeSchema(schema) {
  if (schema && typeof schema === 'object') {
    if ('const' in schema && schema.type !== undefined) {
      delete schema.const;
    }
    Object.keys(schema).forEach(key => {
      if (typeof schema[key] === 'object') {
        normalizeSchema(schema[key]);
      }
    });
  }
  return schema;
}

This is acceptable since const is a validation constraint, not a type definition.

Option 2: Fix in Rust Renderer (Recommended)

Audit all type handlers in rustType() to ensure they never return raw primitive values:

// In RustRenderer.ts - ensure all handlers return valid Sourcelike types
rustType(t, withIssues = false) {
    return matchType(
        t,
        // ... handlers should return strings, arrays, Name objects, or Source objects
        (_boolType) => "bool",  // ✓ Correct - returns string
        // Ensure NO handler returns raw boolean/number/null literals
    );
}

Option 3: Add Type Guard (Defensive)

Add a safety check in splitIntoWords() in Strings.js:

function splitIntoWords(s) {
    if (typeof s !== "string") {
        s = String(s);  // Coerce to string to prevent crash
    }
    // ... rest of function
}

Option 4: Better Error Messages

Improve assertNever to provide actionable error messages:

function assertNever(x: never): never {
    return panic(
        `Internal error: Unexpected value in source tree: ${JSON.stringify(x)} (type: ${typeof x}). ` +
        `This may indicate a bug in a language renderer.`
    );
}

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions