Skip to content

v4: toJSONSchema drops default when the defaulted schema contains a transform/pipe #6049

@reteps

Description

@reteps

Summary

When a schema is wrapped in .default() and the inner schema contains a .transform() (i.e. a ZodPipe), z.toJSONSchema(..., { io: "input" }) omits the default keyword from the output. Removing the transform makes default appear correctly, so the transform's mere presence suppresses the default value.

Zod version

zod@4.4.3

Minimal reproduction

import { z } from "zod";

const withoutTransform = z.string().default("hello");
const withTransform = z.string().transform((s) => s).default("hello");

console.log(z.toJSONSchema(withoutTransform, { io: "input" }));
// { "$schema": "...", "default": "hello", "type": "string" }   ✅

console.log(z.toJSONSchema(withTransform, { io: "input" }));
// { "$schema": "...", "type": "string" }                        ❌ default dropped

Expected

Both should emit default: "hello". The transform changes neither the input type (still string) nor the input-side default value, so the default keyword should be preserved:

{ "type": "string", "default": "hello" }

Actual

The default keyword is missing from the output whenever the defaulted schema contains a transform/pipe.

Notes

  • Reproduces in io: "input" mode (shown above). It also drops the default in io: "output" mode, but that path additionally requires unrepresentable: "any" (otherwise it throws on the transform).
  • It also reproduces when the pipe is nested deeper — e.g. an object property with a transform inside a z.union([...]).default(...):
    z.toJSONSchema(
      z.union([z.boolean(), z.object({ a: z.string().transform((x) => x) })]).default(false),
      { io: "input" },
    );
    // `default: false` is dropped
  • Appears to be in the interaction between the default processor and the pipe processor (defaultProcessorpipeProcessor in core/json-schema-processors).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions