Repository: colinhacks/zod
Pull request #4382 (2025-05-16 12:52:16)

Fix: $ZodCatch schema catchValue handling on validation error
## Overview

Fixed a bug in handling the error value of `catchValue` in the pipe schema.

## Details

The value defined in catch is not set in the following schema.

```ts
const stringWithDefault = z
  .pipe(
    z.transform((v) => (v === "none" ? undefined : v)),
    z.string()
  )
  .catch("default");

expect(stringWithDefault.parse(undefined)).toBe("default"); // <-- The value is set to `undefined`.
```

coderabbitai[bot]: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- This is an auto-generated comment: skip review by coderabbit.ai -->

> [!IMPORTANT]
> ## Review skipped
> 
> Auto reviews are disabled on base/target branches other than the default branch.
> 
> 
> 
> Please check the settings in the CodeRabbit UI or the `.coderabbit.yaml` file in this repository. To trigger a single review, invoke the `@coderabbitai review` command.
> 
> You can disable this status message by setting the `reviews.review_status` to `false` in the CodeRabbit configuration file.

<!-- end of auto-generated comment: skip review by coderabbit.ai -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=colinhacks/zod&utm_content=4382):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

Patch:
diff --git a/packages/docs/content/v4/changelog.mdx b/packages/docs/content/v4/changelog.mdx
index 73bae402..d2723b53 100644
--- a/packages/docs/content/v4/changelog.mdx
+++ b/packages/docs/content/v4/changelog.mdx
@@ -253,6 +253,7 @@ In Zod 3, `z.number().safe()` is deprecated. It now behaves identically to `.int
 ### `.int()` accepts safe integers only
 
 The `z.number().int()` API no longer accepts unsafe integers (outside the range of `Number.MIN_SAFE_INTEGER` and `Number.MAX_SAFE_INTEGER`). Using integers out of this range causes spontaneous rounding errors. (Also: You should switch to `z.int()`.)
+
 ## `z.string()` updates
 
 ### deprecates `.email()` etc
@@ -287,6 +288,11 @@ z.string().email(); // ❌ deprecated
 z.email(); // ✅ 
 ```
 
+
+### no padding in `.base64url()` 
+
+Padding is no longer allowed in `z.base64url()` (formerly `z.string().base64url()`). Generally it's desirable for base64url strings to be unpadded and URL-safe. 
+
 ### drops `z.string().ip()` 
 
 This has been replaced with separate `.ipv4()` and `.ipv6()` methods. Use `z.union()` to combine them if you need to accept both.
diff --git a/packages/zod/src/v4/classic/errors.ts b/packages/zod/src/v4/classic/errors.ts
index b3dd78b5..04e909c2 100644
--- a/packages/zod/src/v4/classic/errors.ts
+++ b/packages/zod/src/v4/classic/errors.ts
@@ -1,5 +1,5 @@
 import * as core from "zod/v4/core";
-import { type $ZodError, _$ZodError } from "zod/v4/core";
+import { $ZodError } from "zod/v4/core";
 
 /** @deprecated Use `z.core.$ZodIssue` from `@zod/core` instead, especially if you are building a library on top of Zod. */
 export type ZodIssue = core.$ZodIssue;
@@ -21,39 +21,43 @@ export interface ZodError<T = unknown> extends $ZodError<T> {
   isEmpty: boolean;
 }
 
-export const _ZodError: core.$constructor<ZodError> = core.$constructor("ZodError", (inst, issues) => {
-  _$ZodError.init(inst, issues);
-  Object.defineProperty(inst, "format", {
-    value: (mapper: any) => core.formatError(inst, mapper),
-    enumerable: false,
-  });
-  Object.defineProperty(inst, "flatten", {
-    value: (mapper: any) => core.flattenError(inst, mapper),
-    enumerable: false,
-  });
-  Object.defineProperty(inst, "addIssue", {
-    value: (issue: any) => inst.issues.push(issue),
-    enumerable: false,
-  });
-  Object.defineProperty(inst, "addIssues", {
-    value: (issues: any) => inst.issues.push(...issues),
-    enumerable: false,
-  });
-  Object.defineProperty(inst, "isEmpty", {
-    get() {
-      return inst.issues.length === 0;
+const initializer = (inst: ZodError, issues: core.$ZodIssue[]) => {
+  $ZodError.init(inst, issues);
+  Object.defineProperties(inst, {
+    format: {
+      value: (mapper: any) => core.formatError(inst, mapper),
+      // enumerable: false,
+    },
+    flatten: {
+      value: (mapper: any) => core.flattenError(inst, mapper),
+      // enumerable: false,
+    },
+    addIssue: {
+      value: (issue: any) => inst.issues.push(issue),
+      // enumerable: false,
+    },
+    addIssues: {
+      value: (issues: any) => inst.issues.push(...issues),
+      // enumerable: false,
+    },
+    isEmpty: {
+      get() {
+        return inst.issues.length === 0;
+      },
+      // enumerable: false,
     },
   });
+  // Object.defineProperty(inst, "isEmpty", {
+  //   get() {
+  //     return inst.issues.length === 0;
+  //   },
+  // });
+};
+export const ZodError: core.$constructor<ZodError> = core.$constructor("ZodError", initializer);
+export const ZodRealError: core.$constructor<ZodError> = core.$constructor("ZodError", initializer, {
+  Parent: Error,
 });
 
-export interface ZodError<T = unknown> extends $ZodError<T> {}
-export class ZodError extends Error {
-  constructor(issues: core.$ZodIssue[]) {
-    super();
-    _ZodError.init(this, issues);
-  }
-}
-
 export type {
   /** @deprecated Use `z.core.$ZodFlattenedError` instead. */
   $ZodFlattenedError as ZodFlattenedError,
diff --git a/packages/zod/src/v4/classic/parse.ts b/packages/zod/src/v4/classic/parse.ts
index 3c5b4b29..7f8de2a3 100644
--- a/packages/zod/src/v4/classic/parse.ts
+++ b/packages/zod/src/v4/classic/parse.ts
@@ -1,5 +1,5 @@
 import * as core from "zod/v4/core";
-import { ZodError, _ZodError } from "./errors.js";
+import { ZodError, ZodRealError } from "./errors.js";
 
 export type ZodSafeParseResult<T> = ZodSafeParseSuccess<T> | ZodSafeParseError<T>;
 export type ZodSafeParseSuccess<T> = { success: true; data: T; error?: never };
@@ -10,24 +10,24 @@ export const parse: <T extends core.$ZodType>(
   value: unknown,
   _ctx?: core.ParseContext<core.$ZodIssue>,
   _params?: { callee?: core.util.AnyFunc; Err?: core.$ZodErrorClass }
-) => core.output<T> = /* @__PURE__ */ core._parse(ZodError) as any;
+) => core.output<T> = /* @__PURE__ */ core._parse(ZodRealError) as any;
 
 export const parseAsync: <T extends core.$ZodType>(
   schema: T,
   value: unknown,
   _ctx?: core.ParseContext<core.$ZodIssue>,
   _params?: { callee?: core.util.AnyFunc; Err?: core.$ZodErrorClass }
-) => Promise<core.output<T>> = /* @__PURE__ */ core._parseAsync(ZodError) as any;
+) => Promise<core.output<T>> = /* @__PURE__ */ core._parseAsync(ZodRealError) as any;
 
 export const safeParse: <T extends core.$ZodType>(
   schema: T,
   value: unknown,
   _ctx?: core.ParseContext<core.$ZodIssue>
   // _params?: { callee?: core.util.AnyFunc; Err?: core.$ZodErrorClass }
-) => ZodSafeParseResult<core.output<T>> = /* @__PURE__ */ core._safeParse(_ZodError) as any;
+) => ZodSafeParseResult<core.output<T>> = /* @__PURE__ */ core._safeParse(ZodError) as any;
 
 export const safeParseAsync: <T extends core.$ZodType>(
   schema: T,
   value: unknown,
   _ctx?: core.ParseContext<core.$ZodIssue>
-) => Promise<ZodSafeParseResult<core.output<T>>> = /* @__PURE__ */ core._safeParseAsync(_ZodError) as any;
+) => Promise<ZodSafeParseResult<core.output<T>>> = /* @__PURE__ */ core._safeParseAsync(ZodError) as any;
diff --git a/packages/zod/src/v4/classic/schemas.ts b/packages/zod/src/v4/classic/schemas.ts
index 60d07a6d..b2187d22 100644
--- a/packages/zod/src/v4/classic/schemas.ts
+++ b/packages/zod/src/v4/classic/schemas.ts
@@ -1613,7 +1613,7 @@ export const ZodTransform: core.$constructor<ZodTransform> = /*@__PURE__*/ core.
           _issue.code ??= "custom";
           _issue.input ??= payload.value;
           _issue.inst ??= inst;
-          _issue.continue ??= !def.abort;
+          _issue.continue ??= true;
           payload.issues.push(util.issue(_issue));
         }
       };
@@ -1632,13 +1632,11 @@ export const ZodTransform: core.$constructor<ZodTransform> = /*@__PURE__*/ core.
 );
 
 export function transform<I = unknown, O = I>(
-  fn: (input: I, ctx: core.ParsePayload) => O,
-  params?: string | core.$ZodTransformParams
+  fn: (input: I, ctx: core.ParsePayload) => O
 ): ZodTransform<Awaited<O>, I> {
   return new ZodTransform({
     type: "transform",
     transform: fn as any,
-    ...util.normalizeParams(params),
   }) as any;
 }
 
@@ -2011,16 +2009,12 @@ export function superRefine<T>(
   return ch;
 }
 
-// instanceof
-abstract class Class {
-  constructor(..._args: any[]) {}
-}
 type ZodInstanceOfParams = util.Params<
   ZodCustom,
   core.$ZodIssueCustom,
   "type" | "check" | "checks" | "fn" | "abort" | "error" | "params" | "path"
 >;
-function _instanceof<T extends typeof Class>(
+function _instanceof<T extends typeof util.Class>(
   cls: T,
   params: ZodInstanceOfParams = {
     error: `Input not instance of ${cls.name}`,
@@ -2063,13 +2057,11 @@ export function json(params?: string | core.$ZodCustomParams): ZodJSONSchema {
 }
 
 // preprocess
-export interface ZodPreprocessParams extends core.$ZodTransformParams {}
 
 // /** @deprecated Use `z.pipe()` and `z.transform()` instead. */
 export function preprocess<A, U extends core.$ZodType>(
   fn: (arg: unknown, ctx: RefinementCtx) => A,
-  schema: U,
-  params?: ZodPreprocessParams
+  schema: U
 ): ZodPipe<ZodTransform<A, unknown>, U> {
-  return pipe(transform(fn as any, params), schema as any);
+  return pipe(transform(fn as any), schema as any);
 }
diff --git a/packages/zod/src/v4/core/api.ts b/packages/zod/src/v4/core/api.ts
index 0a6554a8..663397f8 100644
--- a/packages/zod/src/v4/core/api.ts
+++ b/packages/zod/src/v4/core/api.ts
@@ -1217,13 +1217,11 @@ export function _file(Class: util.SchemaClass<schemas.$ZodFile>, params?: string
 export type $ZodTransformParams = util.TypeParams<schemas.$ZodTransform, "transform">;
 export function _transform<I = unknown, O = I>(
   Class: util.SchemaClass<schemas.$ZodTransform>,
-  fn: (input: I, ctx?: schemas.ParsePayload) => O,
-  params?: string | $ZodTransformParams
+  fn: (input: I, ctx?: schemas.ParsePayload) => O
 ): schemas.$ZodTransform<Awaited<O>, I> {
   return new Class({
     type: "transform",
     transform: fn as any,
-    ...util.normalizeParams(params),
   }) as any;
 }
 
diff --git a/packages/zod/src/v4/core/core.ts b/packages/zod/src/v4/core/core.ts
index a523da9e..707c5a05 100644
--- a/packages/zod/src/v4/core/core.ts
+++ b/packages/zod/src/v4/core/core.ts
@@ -1,5 +1,6 @@
 import type * as errors from "./errors.js";
 import type * as schemas from "./schemas.js";
+import type { Class } from "./util.js";
 //////////////////////////////   CONSTRUCTORS   ///////////////////////////////////////
 
 type ZodTrait = { _zod: { def: any; [k: string]: any } };
@@ -10,10 +11,14 @@ export interface $constructor<T extends ZodTrait, D = T["_zod"]["def"]> {
 
 export /*@__NO_SIDE_EFFECTS__*/ function $constructor<T extends ZodTrait, D = T["_zod"]["def"]>(
   name: string,
-  initializer: (inst: T, def: D) => void
+  initializer: (inst: T, def: D) => void,
+  params?: { Parent?: typeof Class }
 ): $constructor<T, D> {
-  class _ {
+  const Parent = params?.Parent ?? Object;
+
+  class _ extends Parent {
     constructor(def: D) {
+      super();
       const th = this as any;
       _.init(th, def);
       th._zod.deferred ??= [];
@@ -22,7 +27,11 @@ export /*@__NO_SIDE_EFFECTS__*/ function $constructor<T extends ZodTrait, D = T[
       }
     }
     static init(inst: T, def: D) {
-      inst._zod ??= {} as any;
+      Object.defineProperty(inst, "_zod", {
+        value: inst._zod ?? {},
+        enumerable: false,
+      });
+      // inst._zod ??= {} as any;
       inst._zod.traits ??= new Set();
       // const seen = inst._zod.traits.has(name);
 
@@ -36,7 +45,8 @@ export /*@__NO_SIDE_EFFECTS__*/ function $constructor<T extends ZodTrait, D = T[
       inst._zod.def = def;
     }
 
-    static [Symbol.hasInstance](inst: any) {
+    static override [Symbol.hasInstance](inst: any) {
+      if (params?.Parent && inst instanceof params.Parent) return true;
       return inst?._zod?.traits?.has(name);
     }
   }
diff --git a/packages/zod/src/v4/core/errors.ts b/packages/zod/src/v4/core/errors.ts
index 024bd978..886f555a 100644
--- a/packages/zod/src/v4/core/errors.ts
+++ b/packages/zod/src/v4/core/errors.ts
@@ -180,59 +180,33 @@ export interface $ZodError<T = unknown> extends Error {
   name: string;
 }
 
-export const _$ZodError: $constructor<$ZodError> = $constructor("$ZodError", (inst, def) => {
-  Object.defineProperties(inst, {
-    issues: {
-      value: def,
-      enumerable: true,
-    },
-    _zod: {
-      value: inst._zod,
-      enumerable: false,
-    },
-    // message: {
-    //   get() {
-    //     return JSON.stringify(this.issues, util.jsonStringifyReplacer, 2);
-    //   },
-    //   enumerable: false,
-    // },
+const initializer = (inst: $ZodError, def: $ZodIssue[]): void => {
+  Object.defineProperty(inst, "_zod", {
+    value: inst._zod,
+    enumerable: false,
   });
-});
-
-// export interface $ZodError<T = unknown> extends $ZodError<T> {}
-export class $ZodError extends Error {
-  constructor(issues: $ZodIssue[]) {
-    super();
-    _$ZodError.init(this, issues);
-  }
-}
+  Object.defineProperty(inst, "issues", {
+    value: def,
+    enumerable: true,
+  });
+  // Object.defineProperty(inst, "message", {
+  //   get() {
+  //     return (
+  //       "\n" +
+  //       inst.issues
+  //         .map((iss) => {
+  //           return `✖ ${iss.message}${iss.path.length ? ` [${iss.path.join(".")}]` : ""}`;
+  //         })
+  //         .join("\n")
+  //     );
+  //   },
+  //   enumerable: false,
+  // });
+};
 
-// export class _$ZodError extends Error {
-//   public issues!: $ZodIssue[];
-
-//   override get message() {
-//     // console.log("GET MESSAGE");
-//     return JSON.stringify(this.issues, jsonStringifyReplacer, 2);
-//   }
-
-//   // toString() {
-//   //   console.log("TO STRING");
-//   //   return this.stack;
-//   // }
-//   constructor(issues: $ZodIssue[]) {
-//     super();
-//     Object.defineProperty(this, "_tag", { value: ZOD_ERROR, enumerable: false });
-//     // Object.defineProperty(this, "name", { value: "$ZodError", enumerable: false });
-//     // Object.defineProperty(this, "message", { value: JSON.stringify(issues, jsonStringifyReplacer, 2) });
-//     // this.issues = issues;
-//     Object.defineProperty(this, "issues", { value: issues, enumerable: false });
-//   }
-
-//   // @ts-ignore
-//   static [Symbol.hasInstance](inst: any) {
-//     return inst?._tag === ZOD_ERROR;
-//   }
-// }
+export const $ZodError: $constructor<$ZodError> = $constructor("$ZodError", initializer);
+interface $ZodRealError<T = any> extends $ZodError<T> {}
+export const $ZodRealError: $constructor<$ZodRealError> = $constructor("$ZodError", initializer, { Parent: Error });
 
 ///////////////////    ERROR UTILITIES   ////////////////////////
 
@@ -317,24 +291,6 @@ export function formatError<T>(error: $ZodError, _mapper?: any) {
   return fieldErrors;
 }
 
-type _ZodErrorTree<T, U = string> = T extends [any, ...any[]]
-  ? { [K in keyof T]?: $ZodFormattedError<T[K], U> }
-  : T extends any[]
-    ? { [k: number]: $ZodFormattedError<T[number], U> }
-    : T extends object
-      ? util.Flatten<{ [K in keyof T]?: $ZodFormattedError<T[K], U> }>
-      : any;
-
-// export type $ZodErrorTree<T, U = string> = {
-//   errors: U[];
-//   properties: T extends [any, ...any[]]
-//     ? { [K in keyof T]?: $ZodErrorTree<T[K], U> }
-//     : T extends any[]
-//       ? Array<$ZodErrorTree<T[number], U>>
-//       : T extends object
-//         ? { [K in keyof T]?: $ZodErrorTree<T[K], U> }
-//         : any;
-// };
 export type $ZodErrorTree<T, U = string> = T extends [any, ...any[]]
   ? { errors: U[]; items?: { [K in keyof T]?: $ZodErrorTree<T[K], U> } }
   : T extends any[]
@@ -352,24 +308,27 @@ export function treeifyError<T>(error: $ZodError, _mapper?: any) {
       return issue.message;
     };
   const result: $ZodErrorTree<T> = { errors: [] } as any;
-  const processError = (error: { issues: $ZodIssue[] }) => {
+  const processError = (error: { issues: $ZodIssue[] }, path: PropertyKey[] = []) => {
     for (const issue of error.issues) {
       if (issue.code === "invalid_union") {
-        issue.errors.map((issues) => processError({ issues }));
+        issue.errors.map((issues) => processError({ issues }, issue.path));
       } else if (issue.code === "invalid_key") {
-        processError({ issues: issue.issues });
+        processError({ issues: issue.issues }, issue.path);
       } else if (issue.code === "invalid_element") {
-        processError({ issues: issue.issues });
-      } else if (issue.path.length === 0) {
-        result.errors.push(mapper(issue));
+        processError({ issues: issue.issues }, issue.path);
       } else {
+        const fullpath = [...path, ...issue.path];
+        if (fullpath.length === 0) {
+          result.errors.push(mapper(issue));
+          continue;
+        }
+
         let curr: any = result;
         let i = 0;
+        while (i < fullpath.length) {
+          const el = fullpath[i];
 
-        while (i < issue.path.length) {
-          const el = issue.path[i];
-
-          const terminal = i === issue.path.length - 1;
+          const terminal = i === fullpath.length - 1;
           if (typeof el === "string") {
             curr.properties ??= {};
             curr.properties[el] ??= { errors: [] };
@@ -383,27 +342,7 @@ export function treeifyError<T>(error: $ZodError, _mapper?: any) {
           if (terminal) {
             curr.errors.push(mapper(issue));
           }
-          // curr = curr.properties[el];
-          // const terminal = i === issue.path.length - 1;
-
-          // if (!curr) {
-          //   if (typeof el === "string") {
-          //     result.properties = {};
-          //   } else {
-          //     (result as any).properties = [];
-          //   }
-          // }
-
-          // // const curr: any = result.properties;
-          // if (!terminal) {
-          //   curr[el] = curr[el] || { errors: [] };
-          // } else {
-          //   curr[el] = curr[el] || { errors: [] };
-          //   curr[el].errors.push(mapper(issue));
-          // }
-
-          // curr = curr[el];
-          // curr = curr.properties[el];
+
           i++;
         }
       }
diff --git a/packages/zod/src/v4/core/json-schema.ts b/packages/zod/src/v4/core/json-schema.ts
index 3997b3dd..bbcafdca 100644
--- a/packages/zod/src/v4/core/json-schema.ts
+++ b/packages/zod/src/v4/core/json-schema.ts
@@ -9,8 +9,6 @@ export type Schema =
 // | BaseSchema;
 
 export interface BaseSchema {
-  /** A special key used as an intermediate representation of extends-style relationships. Omitted as a $ref with additional properties. */
-  _ref?: BaseSchema;
   type?: string | undefined;
   $id?: string | undefined;
   id?: string | undefined;
@@ -37,6 +35,10 @@ export interface BaseSchema {
   enum?: Array<string | number | boolean | null> | undefined;
   const?: string | number | boolean | null | undefined;
   [k: string]: unknown;
+
+  /** A special key used as an intermediate representation of extends-style relationships. Omitted as a $ref with additional properties. */
+  // _ref?: BaseSchema;
+  _prefault?: unknown | undefined;
 }
 
 export interface ObjectSchema extends BaseSchema {
diff --git a/packages/zod/src/v4/core/parse.ts b/packages/zod/src/v4/core/parse.ts
index 6d01de16..31a9e290 100644
--- a/packages/zod/src/v4/core/parse.ts
+++ b/packages/zod/src/v4/core/parse.ts
@@ -27,7 +27,7 @@ export const _parse: (_Err: $ZodErrorClass) => $Parse = (_Err) => (schema, value
   return result.value;
 };
 
-export const parse: $Parse = /* @__PURE__*/ _parse(errors.$ZodError);
+export const parse: $Parse = /* @__PURE__*/ _parse(errors.$ZodRealError);
 
 export type $ParseAsync = <T extends schemas.$ZodType>(
   schema: T,
@@ -48,7 +48,7 @@ export const _parseAsync: (_Err: $ZodErrorClass) => $ParseAsync = (_Err) => asyn
   return result.value as core.output<typeof schema>;
 };
 
-export const parseAsync: $ParseAsync = /* @__PURE__*/ _parseAsync(errors.$ZodError);
+export const parseAsync: $ParseAsync = /* @__PURE__*/ _parseAsync(errors.$ZodRealError);
 
 export type $SafeParse = <T extends schemas.$ZodType>(
   schema: T,
@@ -70,7 +70,7 @@ export const _safeParse: (_Err: $ZodErrorClass) => $SafeParse = (_Err) => (schem
       }
     : { success: true, data: result.value };
 };
-export const safeParse: $SafeParse = /* @__PURE__*/ _safeParse(errors._$ZodError);
+export const safeParse: $SafeParse = /* @__PURE__*/ _safeParse(errors.$ZodError);
 
 export type $SafeParseAsync = <T extends schemas.$ZodType>(
   schema: T,
@@ -91,4 +91,4 @@ export const _safeParseAsync: (_Err: $ZodErrorClass) => $SafeParseAsync = (_Err)
     : { success: true, data: result.value };
 };
 
-export const safeParseAsync: $SafeParseAsync = /* @__PURE__*/ _safeParseAsync(errors._$ZodError);
+export const safeParseAsync: $SafeParseAsync = /* @__PURE__*/ _safeParseAsync(errors.$ZodError);
diff --git a/packages/zod/src/v4/core/regexes.ts b/packages/zod/src/v4/core/regexes.ts
index e4a25296..e6a37994 100644
--- a/packages/zod/src/v4/core/regexes.ts
+++ b/packages/zod/src/v4/core/regexes.ts
@@ -67,8 +67,8 @@ export const cidrv6: RegExp =
 export const ip: RegExp = new RegExp(`(${ipv4.source})|(${ipv6.source})`);
 
 // https://stackoverflow.com/questions/7860392/determine-if-string-is-in-base64-using-javascript
-export const base64: RegExp = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
-export const base64url: RegExp = /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/;
+export const base64: RegExp = /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/;
+export const base64url: RegExp = /^[A-Za-z0-9_-]*$/;
 
 // based on https://stackoverflow.com/questions/106179/regular-expression-to-match-dns-hostname-or-ip-address
 // export const hostname: RegExp =
diff --git a/packages/zod/src/v4/core/schemas.ts b/packages/zod/src/v4/core/schemas.ts
index 3a34948e..f134a07b 100644
--- a/packages/zod/src/v4/core/schemas.ts
+++ b/packages/zod/src/v4/core/schemas.ts
@@ -810,6 +810,16 @@ export const $ZodCIDRv6: core.$constructor<$ZodCIDRv6> = /*@__PURE__*/ core.$con
 // });
 
 //////////////////////////////   ZodBase64   //////////////////////////////
+export function isValidBase64(data: string): boolean {
+  if (data === "") return true;
+  if (data.length % 4 !== 0) return false;
+  try {
+    atob(data);
+    return true;
+  } catch {
+    return false;
+  }
+}
 
 export interface $ZodBase64Def extends $ZodStringFormatDef<"base64"> {}
 export interface $ZodBase64Internals extends $ZodStringFormatInternals<"base64"> {}
@@ -827,10 +837,27 @@ export const $ZodBase64: core.$constructor<$ZodBase64> = /*@__PURE__*/ core.$con
     inst._zod.onattach.push((inst) => {
       inst._zod.computed.contentEncoding = "base64";
     });
+
+    inst._zod.check = (payload) => {
+      if (isValidBase64(payload.value)) return;
+
+      payload.issues.push({
+        code: "invalid_format",
+        format: "base64",
+        input: payload.value,
+        inst,
+      });
+    };
   }
 );
 
 //////////////////////////////   ZodBase64   //////////////////////////////
+export function isValidBase64URL(data: string): boolean {
+  if (!regexes.base64url.test(data)) return false;
+  const base64 = data.replace(/[-_]/g, (c) => (c === "-" ? "+" : "/"));
+  const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, "=");
+  return isValidBase64(padded);
+}
 
 export interface $ZodBase64URLDef extends $ZodStringFormatDef<"base64url"> {}
 export interface $ZodBase64URLInternals extends $ZodStringFormatInternals<"base64url"> {}
@@ -848,6 +875,17 @@ export const $ZodBase64URL: core.$constructor<$ZodBase64URL> = /*@__PURE__*/ cor
     inst._zod.onattach.push((inst) => {
       inst._zod.computed.contentEncoding = "base64url";
     });
+
+    inst._zod.check = (payload) => {
+      if (isValidBase64URL(payload.value)) return;
+
+      payload.issues.push({
+        code: "invalid_format",
+        format: "base64url",
+        input: payload.value,
+        inst,
+      });
+    };
   }
 );
 
@@ -1941,21 +1979,30 @@ export interface $ZodDiscriminatedUnion<T extends readonly $ZodType[] = readonly
   _zod: $ZodDiscriminatedUnionInternals<T>;
 }
 
+function matchDiscriminatorAtKey(input: any, key: PropertyKey, disc: util.DiscriminatorMapElement): boolean {
+  let matched = true;
+  const data = input?.[key];
+
+  if (disc.values.size && !disc.values.has(data)) {
+    matched = false;
+  }
+  if (disc.maps.length > 0) {
+    for (const m of disc.maps) {
+      if (!matchDiscriminators(data, m)) {
+        matched = false;
+      }
+    }
+  }
+
+  return matched;
+}
+
 function matchDiscriminators(input: any, discs: util.DiscriminatorMap): boolean {
   let matched = true;
   for (const [key, value] of discs) {
-    const data = input?.[key];
-
-    if (value.values.size && !value.values.has(data)) {
+    if (!matchDiscriminatorAtKey(input, key, value)) {
       matched = false;
     }
-    if (value.maps.length > 0) {
-      for (const m of value.maps) {
-        if (!matchDiscriminators(data, m)) {
-          matched = false;
-        }
-      }
-    }
   }
 
   return matched;
@@ -1969,8 +2016,9 @@ export const $ZodDiscriminatedUnion: core.$constructor<$ZodDiscriminatedUnion> =
     const _super = inst._zod.parse;
     const _disc: util.DiscriminatorMap = new Map();
     for (const el of def.options) {
-      if (!el._zod.disc) throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(el)}"`);
-      for (const [key, o] of el._zod.disc) {
+      const subdisc = el._zod.disc;
+      if (!subdisc) throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(el)}"`);
+      for (const [key, o] of subdisc) {
         if (!_disc.has(key))
           _disc.set(key, {
             values: new Set(),
@@ -1987,13 +2035,10 @@ export const $ZodDiscriminatedUnion: core.$constructor<$ZodDiscriminatedUnion> =
     }
     inst._zod.disc = _disc;
 
-    const discMap: Map<$ZodType, util.DiscriminatorMap> = new Map();
-    for (const option of def.options) {
-      const disc = option._zod.disc;
-      if (!disc) {
-        throw new Error(`Invalid discriminated union element: ${option._zod.def.type}`);
-      }
-      discMap.set(option, disc);
+    const subdiscs = def.options.map((o) => o._zod.disc!);
+    const discKeys = [...inst._zod.disc.keys()].filter((k) => subdiscs.every((d) => d.has(k)));
+    if (discKeys.length === 0) {
+      throw new Error(`Invalid discriminated union: no shared discriminator key: ${discKeys.join(", ")}`);
     }
 
     inst._zod.parse = (payload, ctx) => {
@@ -2009,15 +2054,24 @@ export const $ZodDiscriminatedUnion: core.$constructor<$ZodDiscriminatedUnion> =
       }
 
       const filteredOptions: $ZodType[] = [];
-      for (const option of def.options) {
-        if (discMap.has(option)) {
-          if (matchDiscriminators(input, discMap.get(option)!)) {
+      for (const k of discKeys) {
+        let matched = false;
+        for (const option of def.options) {
+          if (matchDiscriminatorAtKey(input, k, option._zod.disc!.get(k)!)) {
+            matched = true;
             filteredOptions.push(option);
           }
-        } else {
-          // no discriminator
-          filteredOptions.push(option);
         }
+        // no matching discriminator
+        if (!matched && !def.unionFallback)
+          payload.issues.push({
+            code: "invalid_union",
+            errors: [],
+            note: "No matching discriminator",
+            path: [k],
+            input,
+            inst,
+          });
       }
 
       if (filteredOptions.length === 1) return filteredOptions[0]._zod.run(payload, ctx) as any;
@@ -2026,14 +2080,6 @@ export const $ZodDiscriminatedUnion: core.$constructor<$ZodDiscriminatedUnion> =
         return _super(payload, ctx);
       }
 
-      // no matching discriminator
-      payload.issues.push({
-        code: "invalid_union",
-        errors: [],
-        note: "No matching discriminator",
-        input,
-        inst,
-      });
       return payload;
     };
   });
@@ -2634,7 +2680,7 @@ function handleSetResult(result: ParsePayload, final: ParsePayload<Set<any>>) {
 ////////////////////////////////////////
 ////////////////////////////////////////
 export type $InferEnumOutput<T extends util.EnumLike> = T[keyof T] & {};
-export type $InferEnumInput<T extends util.EnumLike> = $InferEnumOutput<T>;
+export type $InferEnumInput<T extends util.EnumLike> = T[keyof T] & {};
 
 export interface $ZodEnumDef<T extends util.EnumLike = util.EnumLike> extends $ZodTypeDef {
   type: "enum";
@@ -2834,7 +2880,6 @@ export const $ZodFile: core.$constructor<$ZodFile> = /*@__PURE__*/ core.$constru
 export interface $ZodTransformDef extends $ZodTypeDef {
   type: "transform";
   transform: (input: unknown, payload: ParsePayload<unknown>) => util.MaybeAsync<unknown>;
-  abort?: boolean | undefined;
 }
 export interface $ZodTransformInternals<O = unknown, I = unknown> extends $ZodTypeInternals<O, I> {
   def: $ZodTransformDef;
@@ -3248,6 +3293,7 @@ export const $ZodCatch: core.$constructor<$ZodCatch> = /*@__PURE__*/ core.$const
     const result = def.innerType._zod.run(payload, ctx);
     if (result instanceof Promise) {
       return result.then((result) => {
+        payload.value = result.value;
         if (result.issues.length) {
           payload.value = def.catchValue({
             ...payload,
@@ -3258,12 +3304,12 @@ export const $ZodCatch: core.$constructor<$ZodCatch> = /*@__PURE__*/ core.$const
           });
           payload.issues = [];
         }
-        payload.value = result.value;
 
         return payload;
       });
     }
 
+    payload.value = result.value;
     if (result.issues.length) {
       payload.value = def.catchValue({
         ...payload,
@@ -3274,7 +3320,6 @@ export const $ZodCatch: core.$constructor<$ZodCatch> = /*@__PURE__*/ core.$const
       });
       payload.issues = [];
     }
-    payload.value = result.value;
 
     return payload;
   };
diff --git a/packages/zod/src/v4/core/to-json-schema.ts b/packages/zod/src/v4/core/to-json-schema.ts
index 19f2e919..97482c99 100644
--- a/packages/zod/src/v4/core/to-json-schema.ts
+++ b/packages/zod/src/v4/core/to-json-schema.ts
@@ -26,7 +26,6 @@ interface JSONSchemaGeneratorParams {
 interface ProcessParams {
   schemaPath: schemas.$ZodType[];
   path: (string | number)[];
-  // initial?: Seen | undefined;
 }
 
 interface EmitParams {
@@ -34,21 +33,16 @@ interface EmitParams {
    * - `"ref"` — Default. Cycles will be broken using $defs
    * - `"throw"` — Cycles will throw an error if encountered */
   cycles?: "ref" | "throw";
-
   /* How to handle reused schemas.
    * - `"inline"` — Default. Reused schemas will be inlined
    * - `"ref"` — Reused schemas will be extracted as $defs */
   reused?: "ref" | "inline";
-  /** A function used to convert `id` values to URIs to be used in *external* $refs.
-   *
-   * Default is `(id) => id`.
-   */
-  // uri?: (id: string) => string;
+
   external?:
     | {
+        /**  */
         registry: $ZodRegistry<{ id?: string | undefined }>;
         uri: (id: string) => string;
-        // __shared: boolean;
         defs: Record<string, JSONSchema.BaseSchema>;
       }
     | undefined;
@@ -71,8 +65,8 @@ interface Seen {
   count: number;
   /** Cycle path */
   cycle?: (string | number)[] | undefined;
-
-  // external?: string | undefined;
+  isParent?: boolean | undefined;
+  ref?: schemas.$ZodType | undefined | null;
 }
 
 export class JSONSchemaGenerator {
@@ -86,7 +80,6 @@ export class JSONSchemaGenerator {
   seen: Map<schemas.$ZodType, Seen>;
 
   constructor(params?: JSONSchemaGeneratorParams) {
-    // this.external = params?.external;
     this.metadataRegistry = params?.metadata ?? globalRegistry;
     this.target = params?.target ?? "draft-2020-12";
     this.unrepresentable = params?.unrepresentable ?? "throw";
@@ -98,13 +91,6 @@ export class JSONSchemaGenerator {
 
   process(schema: schemas.$ZodType, _params: ProcessParams = { path: [], schemaPath: [] }): JSONSchema.BaseSchema {
     const def = (schema as schemas.$ZodTypes)._zod.def;
-    // if (def.type === "lazy") {
-    //   return this.process((schema as schemas.$ZodLazy)._zod._getter, _params);
-    // } else if (def.type === "promise") {
-    //   return this.process(def.innerType, _params);
-    // } else if (def.type === "pipe") {
-    //   return this.process(def.out, _params);
-    // }
 
     // check for schema in seens
     const seen = this.seen.get(schema);
@@ -127,15 +113,9 @@ export class JSONSchemaGenerator {
     const result: Seen = { schema: {}, count: 1, cycle: undefined };
     this.seen.set(schema, result);
 
-    // if(schema._zod.parent){
-    //   // schema was cloned from another schema
-    //   result.
-    // }
-
     if (schema._zod.toJSONSchema) {
       // custom method overrides default behavior
       result.schema = schema._zod.toJSONSchema() as any;
-      // return
     }
 
     // check if external
@@ -144,13 +124,6 @@ export class JSONSchemaGenerator {
     //   result.external = ext;
     // }
 
-    // // metadata
-    // const meta = this.metadataRegistry.get(schema);
-    // if (meta) {
-    //   Object.assign(_json, meta);
-    // }
-
-    // const def = (schema as schemas.$ZodTypes)._zod.def;
     const params = {
       ..._params,
       schemaPath: [..._params.schemaPath, schema],
@@ -159,7 +132,9 @@ export class JSONSchemaGenerator {
 
     if (schema._zod.parent) {
       // schema was cloned from another schema
-      result.schema._ref = this.process(schema._zod.parent, params);
+      result.ref = schema._zod.parent;
+      this.process(schema._zod.parent, params);
+      this.seen.get(schema._zod.parent)!.isParent = true;
     } else {
       const _json = result.schema;
       switch (def.type) {
@@ -234,7 +209,6 @@ export class JSONSchemaGenerator {
         }
         case "null": {
           _json.type = "null";
-          // const json = { type: "null" } as JSONSchema.NullSchema;
           break;
         }
         case "any": {
@@ -276,10 +250,7 @@ export class JSONSchemaGenerator {
           json.type = "object";
           json.properties = {};
           const shape = def.shape; // params.shapeCache.get(schema)!;
-          // if (!shape) {
-          //   shape = def.shape;
-          //   params.shapeCache.set(schema, shape);
-          // }
+
           for (const key in shape) {
             json.properties[key] = this.process(shape[key], {
               ...params,
@@ -455,8 +426,8 @@ export class JSONSchemaGenerator {
           break;
         }
         case "nonoptional": {
-          const inner = this.process(def.innerType, params);
-          Object.assign(_json, inner);
+          this.process(def.innerType, params);
+          result.ref = def.innerType;
           break;
         }
         case "success": {
@@ -465,21 +436,22 @@ export class JSONSchemaGenerator {
           break;
         }
         case "default": {
-          const inner = this.process(def.innerType, params);
-          Object.assign(_json, inner);
+          this.process(def.innerType, params);
+          result.ref = def.innerType;
           _json.default = def.defaultValue;
           break;
         }
         case "prefault": {
-          const inner = this.process(def.innerType, params);
-          Object.assign(_json, inner);
-          _json.default = schema["~standard"].validate(undefined);
+          this.process(def.innerType, params);
+          result.ref = def.innerType;
+          if (this.io === "input") _json._prefault = def.defaultValue;
+
           break;
         }
         case "catch": {
           // use conditionals
-          const inner = this.process(def.innerType, params);
-          Object.assign(_json, inner);
+          this.process(def.innerType, params);
+          result.ref = def.innerType;
           let catchValue: any;
           try {
             catchValue = def.catchValue(undefined as any);
@@ -495,23 +467,6 @@ export class JSONSchemaGenerator {
           }
           break;
         }
-        case "pipe": {
-          const innerType = this.io === "input" ? def.in : def.out;
-          const inner = this.process(innerType, params);
-          _json._ref = inner;
-
-          break;
-        }
-        case "readonly": {
-          _json._ref = this.process(def.innerType, params);
-          _json.readOnly = true;
-          // const inner = this.process(def.innerType, params);
-          // Object.assign(_json, inner);
-          // _json.allOf = [inner];
-          // result.extra.readOnly = true;
-          // _json.readOnly = true;
-          break;
-        }
         case "template_literal": {
           const json = _json as JSONSchema.StringSchema;
           const pattern = schema._zod.pattern;
@@ -520,23 +475,33 @@ export class JSONSchemaGenerator {
           json.pattern = pattern.source;
           break;
         }
-        case "promise": {
-          const inner = this.process(def.innerType, params);
-          // result.schema = inner;
-          _json._ref = inner;
+        case "pipe": {
+          const innerType = this.io === "input" ? def.in : def.out;
+          this.process(innerType, params);
+          result.ref = innerType;
+          break;
+        }
+        case "readonly": {
+          this.process(def.innerType, params);
+          result.ref = def.innerType;
+          _json.readOnly = true;
           break;
         }
         // passthrough types
+        case "promise": {
+          this.process(def.innerType, params);
+          result.ref = def.innerType;
+          break;
+        }
         case "optional": {
-          // result.schema = this.process(def.innerType, params);
-          _json._ref = this.process(def.innerType, params);
+          this.process(def.innerType, params);
+          result.ref = def.innerType;
           break;
         }
         case "lazy": {
           const innerType = (schema as schemas.$ZodLazy)._zod.innerType;
-          const inner = this.process(innerType, params);
-          // result.schema = inner;
-          _json._ref = inner;
+          this.process(innerType, params);
+          result.ref = innerType;
           break;
         }
         case "custom": {
@@ -553,19 +518,19 @@ export class JSONSchemaGenerator {
 
     // metadata
     const meta = this.metadataRegistry.get(schema);
-    if (meta) {
-      Object.assign(result.schema, meta);
+    if (meta) Object.assign(result.schema, meta);
+    if (this.io === "input" && def.type === "pipe") {
+      // examples/defaults only apply to output type of pipe
+      delete result.schema.examples;
+      delete result.schema.default;
+      if (result.schema._prefault) result.schema.default = result.schema._prefault;
     }
+    if (this.io === "input" && result.schema._prefault) result.schema.default ??= result.schema._prefault;
+    delete result.schema._prefault;
 
     // pulling fresh from this.seen in case it was overwritten
     const _result = this.seen.get(schema)!;
 
-    this.override({
-      zodSchema: schema,
-      jsonSchema: _result.schema,
-    });
-
-    // Object.assign(_result.cached, _result.schema);
     return _result.schema;
   }
 
@@ -578,9 +543,7 @@ export class JSONSchemaGenerator {
       external: _params?.external ?? undefined,
     } satisfies EmitParams;
 
-    // iterate over seen map
-    // const result: JSONSchema.BaseSchema = {};
-    // const defs: JSONSchema.BaseSchema["$defs"] = params.external?.defs ?? {};
+    // iterate over seen map;
     const root = this.seen.get(schema);
 
     if (!root) throw new Error("Unprocessed schema. This is a bug in Zod.");
@@ -620,17 +583,21 @@ export class JSONSchemaGenerator {
 
     const extractToDef = (entry: [schemas.$ZodType<unknown, unknown>, Seen]): void => {
       if (entry[1].schema.$ref) {
-        // throw new Error("Already extracted");
         return;
       }
       const seen = entry[1];
       const { ref, defId } = makeURI(entry);
-      // defId won't be set if the schema is a reference to an external schema
 
       seen.def = { ...seen.schema };
+      // defId won't be set if the schema is a reference to an external schema
       if (defId) seen.defId = defId;
       // wipe away all properties except $ref
-      schemaToRef(seen, ref);
+      const schema = seen.schema;
+      for (const key in schema) {
+        // @ts-ignore
+        delete schema[key];
+        schema.$ref = ref;
+      }
     };
 
     // extract schemas into $defs
@@ -686,13 +653,45 @@ export class JSONSchemaGenerator {
       }
     }
 
+    // flatten _refs
+    const flattenRef = (zodSchema: schemas.$ZodType, params: Pick<ToJSONSchemaParams, "target">) => {
+      const seen = this.seen.get(zodSchema)!;
+      const schema = seen.def ?? seen.schema;
+
+      const _schema = { ...schema };
+      if (seen.ref === null) {
+        return;
+      }
+
+      const ref = seen.ref;
+      seen.ref = null;
+      if (ref) {
+        flattenRef(ref, params);
+
+        const refSchema = this.seen.get(ref)!.schema;
+
+        if (refSchema.$ref && params.target === "draft-7") {
+          schema.allOf = schema.allOf ?? [];
+          schema.allOf.push(refSchema);
+        } else {
+          Object.assign(schema, refSchema);
+          Object.assign(schema, _schema); // this is to prevent overwriting any fields in the original schema
+        }
+      }
+
+      if (!seen.isParent)
+        this.override({
+          zodSchema,
+          jsonSchema: schema,
+        });
+    };
+
     for (const entry of this.seen.entries()) {
-      const seen = entry[1];
-      flattenRef(seen.schema, { target: this.target });
-      if (seen.def) flattenRef(seen.def, { target: this.target });
+      flattenRef(entry[0], { target: this.target });
     }
 
     const result = { ...root.def };
+
     const defs: JSONSchema.BaseSchema["$defs"] = params.external?.defs ?? {};
     for (const entry of this.seen.entries()) {
       const seen = entry[1];
@@ -711,7 +710,7 @@ export class JSONSchemaGenerator {
     }
 
     try {
-      // this essentially "finalizes" this schema
+      // this "finalizes" this schema and ensures all cycles are removed
       // each call to .emit() is functionally independent
       // though the seen map is shared
       return JSON.parse(JSON.stringify(result));
@@ -721,31 +720,6 @@ export class JSONSchemaGenerator {
   }
 }
 
-// flatten _refs
-const flattenRef = (schema: JSONSchema.BaseSchema, params: Pick<ToJSONSchemaParams, "target">) => {
-  const _schema = { ...schema };
-  if (schema._ref) flattenRef(schema._ref, params);
-  const ref = schema._ref;
-  if (ref) {
-    if (ref.$ref && params.target === "draft-7") {
-      schema.allOf = schema.allOf ?? [];
-      schema.allOf.push(ref);
-    } else {
-      Object.assign(schema, ref);
-      Object.assign(schema, _schema); // this is to prevent overwriting any fields in the original schema
-    }
-  }
-  delete schema._ref;
-};
-
-function schemaToRef(seen: Seen, ref: string) {
-  const schema = seen.schema;
-  for (const key in schema) {
-    delete schema[key];
-    schema.$ref = ref;
-  }
-}
-
 interface ToJSONSchemaParams extends Omit<JSONSchemaGeneratorParams & EmitParams, never> {}
 interface RegistryToJSONSchemaParams extends Omit<JSONSchemaGeneratorParams & EmitParams, never> {
   uri?: (id: string) => string;
diff --git a/packages/zod/src/v4/core/util.ts b/packages/zod/src/v4/core/util.ts
index 404f78f8..affb0cd1 100644
--- a/packages/zod/src/v4/core/util.ts
+++ b/packages/zod/src/v4/core/util.ts
@@ -321,6 +321,7 @@ export function isObject(data: any): data is Record<PropertyKey, unknown> {
 
 export const allowsEval: { value: boolean } = cached(() => {
   try {
+    const F = Function;
     new F("");
     return true;
   } catch (_) {
@@ -328,8 +329,6 @@ export const allowsEval: { value: boolean } = cached(() => {
   }
 });
 
-export const F: typeof Function = Function;
-
 export function isPlainObject(data: any): data is Record<PropertyKey, unknown> {
   return typeof data === "object" && data !== null && Object.getPrototypeOf(data) === Object.prototype;
 }
@@ -808,3 +807,8 @@ export function cleanEnum(obj: Record<string, EnumValue>): EnumValue[] {
     })
     .map((el) => el[1]);
 }
+
+// instanceof
+export abstract class Class {
+  constructor(..._args: any[]) {}
+}
diff --git a/packages/zod/src/v4/mini/schemas.ts b/packages/zod/src/v4/mini/schemas.ts
index 5cfa4805..840f72ea 100644
--- a/packages/zod/src/v4/mini/schemas.ts
+++ b/packages/zod/src/v4/mini/schemas.ts
@@ -1154,13 +1154,11 @@ export const ZodMiniTransform: core.$constructor<ZodMiniTransform> = /*@__PURE__
 );
 
 export function transform<I = unknown, O = I>(
-  fn: (input: I, ctx: core.ParsePayload) => O,
-  params?: string | core.$ZodTransformParams
+  fn: (input: I, ctx: core.ParsePayload) => O
 ): ZodMiniTransform<Awaited<O>, I> {
   return new ZodMiniTransform({
     type: "transform",
     transform: fn as any,
-    ...util.normalizeParams(params),
   }) as any;
 }
 
diff --git a/play.ts b/play.ts
index e216e6ee..0c4bfce9 100644
--- a/play.ts
+++ b/play.ts
@@ -1,19 +1,18 @@
 import { z } from "zod/v4";
 
+z;
+
 const schema = z.object({
   name: z.string(),
-  age: z.number(),
+  logLevel: z.union([z.string(), z.number()]),
+  env: z.literal(["production", "development"]),
 });
 
 const data = {
-  name: "John Doe",
-  age: 30,
+  name: 1000,
+  logLevel: false,
 };
 
 const result = schema.safeParse(data);
 
-if (result.success) {
-  console.log("Parsed data:", result.data);
-} else {
-  console.error("Validation errors:", result.error);
-}
+console.dir(z.prettifyError(result.error!), { depth: null });


Test patch:
diff --git a/packages/zod/src/v4/classic/tests/async-parsing.test.ts b/packages/zod/src/v4/classic/tests/async-parsing.test.ts
index dc2931ed..31097635 100644
--- a/packages/zod/src/v4/classic/tests/async-parsing.test.ts
+++ b/packages/zod/src/v4/classic/tests/async-parsing.test.ts
@@ -15,7 +15,7 @@ test("string async parse", async () => {
 
   const badResult = await stringSchema.safeParseAsync(badData);
   expect(badResult.success).toBe(false);
-  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z._ZodError);
+  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError);
 });
 
 /// number
@@ -30,7 +30,7 @@ test("number async parse", async () => {
 
   const badResult = await numberSchema.safeParseAsync(badData);
   expect(badResult.success).toBe(false);
-  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z._ZodError);
+  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError);
 });
 
 /// bigInt
@@ -45,7 +45,7 @@ test("bigInt async parse", async () => {
 
   const badResult = await bigIntSchema.safeParseAsync(badData);
   expect(badResult.success).toBe(false);
-  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z._ZodError);
+  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError);
 });
 
 /// boolean
@@ -60,7 +60,7 @@ test("boolean async parse", async () => {
 
   const badResult = await booleanSchema.safeParseAsync(badData);
   expect(badResult.success).toBe(false);
-  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z._ZodError);
+  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError);
 });
 
 /// date
@@ -75,7 +75,7 @@ test("date async parse", async () => {
 
   const badResult = await dateSchema.safeParseAsync(badData);
   expect(badResult.success).toBe(false);
-  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z._ZodError);
+  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError);
 });
 
 /// undefined
@@ -90,7 +90,7 @@ test("undefined async parse", async () => {
 
   const badResult = await undefinedSchema.safeParseAsync(badData);
   expect(badResult.success).toBe(false);
-  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z._ZodError);
+  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError);
 });
 
 /// null
@@ -105,7 +105,7 @@ test("null async parse", async () => {
 
   const badResult = await nullSchema.safeParseAsync(badData);
   expect(badResult.success).toBe(false);
-  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z._ZodError);
+  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError);
 });
 
 /// any
@@ -120,7 +120,7 @@ test("any async parse", async () => {
 
   // const badResult = await anySchema.safeParseAsync(badData);
   // expect(badResult.success).toBe(false);
-  // if (!badResult.success) expect(badResult.error).toBeInstanceOf(z._ZodError);
+  // if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError);
 });
 
 /// unknown
@@ -135,7 +135,7 @@ test("unknown async parse", async () => {
 
   // const badResult = await unknownSchema.safeParseAsync(badData);
   // expect(badResult.success).toBe(false);
-  // if (!badResult.success) expect(badResult.error).toBeInstanceOf(z._ZodError);
+  // if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError);
 });
 
 /// void
@@ -150,7 +150,7 @@ test("void async parse", async () => {
 
   const badResult = await voidSchema.safeParseAsync(badData);
   expect(badResult.success).toBe(false);
-  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z._ZodError);
+  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError);
 });
 
 /// array
@@ -165,7 +165,7 @@ test("array async parse", async () => {
 
   const badResult = await arraySchema.safeParseAsync(badData);
   expect(badResult.success).toBe(false);
-  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z._ZodError);
+  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError);
 });
 
 /// object
@@ -180,7 +180,7 @@ test("object async parse", async () => {
 
   const badResult = await objectSchema.safeParseAsync(badData);
   expect(badResult.success).toBe(false);
-  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z._ZodError);
+  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError);
 });
 
 /// union
@@ -195,7 +195,7 @@ test("union async parse", async () => {
 
   const badResult = await unionSchema.safeParseAsync(badData);
   expect(badResult.success).toBe(false);
-  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z._ZodError);
+  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError);
 });
 
 /// record
@@ -210,7 +210,7 @@ test("record async parse", async () => {
 
   const badResult = await recordSchema.safeParseAsync(badData);
   expect(badResult.success).toBe(false);
-  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z._ZodError);
+  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError);
 });
 
 /// function
@@ -225,7 +225,7 @@ test("record async parse", async () => {
 
 //   const badResult = await functionSchema.safeParseAsync(badData);
 //   expect(badResult.success).toBe(false);
-//   if (!badResult.success) expect(badResult.error).toBeInstanceOf(z._ZodError);
+//   if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError);
 // });
 
 /// literal
@@ -240,7 +240,7 @@ test("literal async parse", async () => {
 
   const badResult = await literalSchema.safeParseAsync(badData);
   expect(badResult.success).toBe(false);
-  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z._ZodError);
+  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError);
 });
 
 /// enum
@@ -255,7 +255,7 @@ test("enum async parse", async () => {
 
   const badResult = await enumSchema.safeParseAsync(badData);
   expect(badResult.success).toBe(false);
-  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z._ZodError);
+  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError);
 });
 
 /// nativeEnum
@@ -274,7 +274,7 @@ test("nativeEnum async parse", async () => {
 
   const badResult = await nativeEnumSchema.safeParseAsync(badData);
   expect(badResult.success).toBe(false);
-  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z._ZodError);
+  if (!badResult.success) expect(badResult.error).toBeInstanceOf(z.ZodError);
 });
 
 /// promise
@@ -292,7 +292,7 @@ test("promise async parse bad", async () => {
   const badData = Promise.resolve("XXX");
   const badResult = await promiseSchema.safeParseAsync(badData);
   expect(badResult.success).toBe(false);
-  expect(badResult.error).toBeInstanceOf(z._ZodError);
+  expect(badResult.error).toBeInstanceOf(z.ZodError);
 });
 
 test("async validation non-empty strings", async () => {
diff --git a/packages/zod/src/v4/classic/tests/discriminated-unions.test.ts b/packages/zod/src/v4/classic/tests/discriminated-unions.test.ts
index d0957376..de777f5b 100644
--- a/packages/zod/src/v4/classic/tests/discriminated-unions.test.ts
+++ b/packages/zod/src/v4/classic/tests/discriminated-unions.test.ts
@@ -105,7 +105,7 @@ test("valid - discriminator value of various primitive types", () => {
     type: "not_a_key",
     val: "val",
   });
-  expect(fail.error).toBeInstanceOf(z._ZodError);
+  expect(fail.error).toBeInstanceOf(z.ZodError);
 });
 
 test("invalid - null", () => {
@@ -156,7 +156,9 @@ test("invalid discriminator value", () => {
             "errors": [],
             "message": "Invalid input",
             "note": "No matching discriminator",
-            "path": [],
+            "path": [
+              "type",
+            ],
           },
         ],
       },
diff --git a/packages/zod/src/v4/classic/tests/error-utils.test.ts b/packages/zod/src/v4/classic/tests/error-utils.test.ts
index c023afc0..d5f4bb29 100644
--- a/packages/zod/src/v4/classic/tests/error-utils.test.ts
+++ b/packages/zod/src/v4/classic/tests/error-utils.test.ts
@@ -374,6 +374,48 @@ test("z.treeifyError", () => {
   `);
 });
 
+test("z.treeifyError 2", () => {
+  const schema = z.strictObject({
+    name: z.string(),
+    logLevel: z.union([z.string(), z.number()]),
+    env: z.literal(["production", "development"]),
+  });
+
+  const data = {
+    name: 1000,
+    logLevel: false,
+    extra: 1000,
+  };
+
+  const result = schema.safeParse(data);
+  const err = z.treeifyError(result.error!);
+  expect(err).toMatchInlineSnapshot(`
+    {
+      "errors": [
+        "Unrecognized key: "extra"",
+      ],
+      "properties": {
+        "env": {
+          "errors": [
+            "Invalid option: expected one of "production"|"development"",
+          ],
+        },
+        "logLevel": {
+          "errors": [
+            "Invalid input: expected string, received boolean",
+            "Invalid input: expected number, received boolean",
+          ],
+        },
+        "name": {
+          "errors": [
+            "Invalid input: expected string, received number",
+          ],
+        },
+      },
+    }
+  `);
+});
+
 test("z.prettifyError", () => {
   expect(z.prettifyError(result.error!)).toMatchInlineSnapshot(`
     "✖ Unrecognized key: "extra"
@@ -419,10 +461,12 @@ test("z.toDotPath", () => {
 
 test("inheritance", () => {
   const e1 = new z.ZodError([]);
-  const e2 = new z._ZodError([]);
-
+  expect(e1).toBeInstanceOf(z.core.$ZodError);
   expect(e1).toBeInstanceOf(z.ZodError);
-  expect(e2).toBeInstanceOf(z._ZodError);
-  expect(e2).not.toBeInstanceOf(z.ZodError);
-  expect(e1).toBeInstanceOf(z._ZodError);
+  expect(e1).not.toBeInstanceOf(Error);
+
+  const e2 = new z.ZodRealError([]);
+  expect(e2).toBeInstanceOf(z.ZodError);
+  expect(e2).toBeInstanceOf(z.ZodRealError);
+  expect(e2).toBeInstanceOf(Error);
 });
diff --git a/packages/zod/src/v4/classic/tests/error.test.ts b/packages/zod/src/v4/classic/tests/error.test.ts
index 711c1083..7071e3ec 100644
--- a/packages/zod/src/v4/classic/tests/error.test.ts
+++ b/packages/zod/src/v4/classic/tests/error.test.ts
@@ -683,3 +683,29 @@ test("string error params", () => {
   const j = z.array(z.string(), "Bad array!");
   expect(j.safeParse(null).error!.issues[0].message).toBe("Bad array!");
 });
+
+test("error inheritance", () => {
+  const e1 = z.string().safeParse(123).error!;
+  expect(e1).toBeInstanceOf(z.core.$ZodError);
+  expect(e1).toBeInstanceOf(z.ZodError);
+  expect(e1).toBeInstanceOf(z.ZodRealError);
+  expect(e1).not.toBeInstanceOf(Error);
+
+  try {
+    z.string().parse(123);
+  } catch (e2) {
+    expect(e1).toBeInstanceOf(z.core.$ZodError);
+    expect(e2).toBeInstanceOf(z.ZodError);
+    expect(e2).toBeInstanceOf(z.ZodRealError);
+    expect(e2).toBeInstanceOf(Error);
+  }
+});
+
+test("error serialization", () => {
+  try {
+    z.string().parse(123);
+  } catch (e) {
+    console.dir(e, { depth: null });
+    expect(e).toMatchInlineSnapshot(`[Error]`);
+  }
+});
diff --git a/packages/zod/src/v4/classic/tests/json-schema.test.ts b/packages/zod/src/v4/classic/tests/json-schema.test.ts
index df6ad2ea..9786d948 100644
--- a/packages/zod/src/v4/classic/tests/json-schema.test.ts
+++ b/packages/zod/src/v4/classic/tests/json-schema.test.ts
@@ -109,7 +109,7 @@ describe("toJSONSchema", () => {
       {
         "contentEncoding": "base64",
         "format": "base64",
-        "pattern": "^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$",
+        "pattern": "^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$",
         "type": "string",
       }
     `);
@@ -293,7 +293,7 @@ describe("toJSONSchema", () => {
       {
         "contentEncoding": "base64",
         "format": "base64",
-        "pattern": "^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$",
+        "pattern": "^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$",
         "type": "string",
       }
     `);
@@ -851,6 +851,27 @@ test("override", () => {
   `);
 });
 
+test("override: do not run on references", () => {
+  let overrideCount = 0;
+  const schema = z
+    .union([z.string().date(), z.string().datetime(), z.string().datetime({ local: true })])
+    .meta({ a: true })
+    .transform((str) => new Date(str))
+    .meta({ b: true })
+    .pipe(z.date())
+    .meta({ c: true })
+    .brand("dateIn");
+  z.toJSONSchema(schema, {
+    unrepresentable: "any",
+    io: "input",
+    override(_) {
+      overrideCount++;
+    },
+  });
+
+  expect(overrideCount).toBe(6);
+});
+
 test("pipe", () => {
   const mySchema = z
     .string()
@@ -1352,6 +1373,53 @@ test("_ref", () => {
   `);
 });
 
+test("defaults/prefaults", () => {
+  const a = z
+    .string()
+    .transform((val) => val.length)
+    .pipe(z.number());
+  const b = a.prefault("hello");
+  const c = a.default(1234);
+
+  // a
+  expect(toJSONSchema(a)).toMatchInlineSnapshot(`
+    {
+      "type": "number",
+    }
+  `);
+  expect(toJSONSchema(a, { io: "input" })).toMatchInlineSnapshot(`
+    {
+      "type": "string",
+    }
+  `);
+
+  // b
+  expect(toJSONSchema(b)).toMatchInlineSnapshot(`
+    {
+      "type": "number",
+    }
+  `);
+  expect(toJSONSchema(b, { io: "input" })).toMatchInlineSnapshot(`
+    {
+      "default": "hello",
+      "type": "string",
+    }
+  `);
+  // c
+  expect(toJSONSchema(c)).toMatchInlineSnapshot(`
+    {
+      "default": 1234,
+      "type": "number",
+    }
+  `);
+  expect(toJSONSchema(c, { io: "input" })).toMatchInlineSnapshot(`
+    {
+      "default": 1234,
+      "type": "string",
+    }
+  `);
+});
+
 test("input type", () => {
   const schema = z.object({
     a: z.string(),
@@ -1384,9 +1452,7 @@ test("input type", () => {
           ],
         },
         "e": {
-          "default": {
-            "value": "hello",
-          },
+          "default": "hello",
           "type": "string",
         },
       },
@@ -1421,9 +1487,6 @@ test("input type", () => {
           ],
         },
         "e": {
-          "default": {
-            "value": "hello",
-          },
           "type": "string",
         },
       },
@@ -1437,3 +1500,47 @@ test("input type", () => {
     }
   `);
 });
+
+test("examples on pipe", () => {
+  const schema = z
+    .string()
+    .meta({ examples: ["test"] })
+    .transform(Number)
+    // .pipe(z.transform(Number).meta({ examples: [4] }))
+    .meta({ examples: [4] });
+
+  const i = z.toJSONSchema(schema, { io: "input", unrepresentable: "any" });
+  expect(i).toMatchInlineSnapshot(`
+    {
+      "examples": [
+        "test",
+      ],
+      "type": "string",
+    }
+  `);
+  const o = z.toJSONSchema(schema, { io: "output", unrepresentable: "any" });
+  expect(o).toMatchInlineSnapshot(`
+    {
+      "examples": [
+        4,
+      ],
+    }
+  `);
+});
+
+test("override with refs", () => {
+  const a = z.string().optional();
+  const result = z.toJSONSchema(a, {
+    override(ctx) {
+      if (ctx.zodSchema._zod.def.type === "string") {
+        ctx.jsonSchema.type = "STRING";
+      }
+    },
+  });
+
+  expect(result).toMatchInlineSnapshot(`
+    {
+      "type": "STRING",
+    }
+  `);
+});
diff --git a/packages/zod/src/v4/classic/tests/pipe.test.ts b/packages/zod/src/v4/classic/tests/pipe.test.ts
index 23559ab6..0a338215 100644
--- a/packages/zod/src/v4/classic/tests/pipe.test.ts
+++ b/packages/zod/src/v4/classic/tests/pipe.test.ts
@@ -15,6 +15,20 @@ test("string to number pipe async", async () => {
   expect(await schema.parseAsync("1234")).toEqual(1234);
 });
 
+test("string with default fallback", () => {
+  const stringWithDefault = z
+    .pipe(
+      z.transform((v) => (v === "none" ? undefined : v)),
+      z.string()
+    )
+    .catch("default");
+
+  expect(stringWithDefault.parse("ok")).toBe("ok");
+  expect(stringWithDefault.parse(undefined)).toBe("default");
+  expect(stringWithDefault.parse("none")).toBe("default");
+  expect(stringWithDefault.parse(15)).toBe("default");
+});
+
 test("continue on non-fatal errors", () => {
   const schema = z
     .string()
diff --git a/packages/zod/src/v4/classic/tests/promise.test.ts b/packages/zod/src/v4/classic/tests/promise.test.ts
index e3919782..b857a2b6 100644
--- a/packages/zod/src/v4/classic/tests/promise.test.ts
+++ b/packages/zod/src/v4/classic/tests/promise.test.ts
@@ -29,13 +29,13 @@ test("promise parsing success", async () => {
 test("promise parsing fail", async () => {
   const bad = await promSchema.safeParseAsync(Promise.resolve({ name: "Bobby", age: "10" }));
   expect(bad.success).toBe(false);
-  expect(bad.error).toBeInstanceOf(z._ZodError);
+  expect(bad.error).toBeInstanceOf(z.ZodError);
 });
 
 test("promise parsing fail 2", async () => {
   const result = await promSchema.safeParseAsync(Promise.resolve({ name: "Bobby", age: "10" }));
   expect(result.success).toBe(false);
-  expect(result.error).toBeInstanceOf(z._ZodError);
+  expect(result.error).toBeInstanceOf(z.ZodError);
 });
 
 test("promise parsing fail", () => {
diff --git a/packages/zod/src/v4/classic/tests/string.test.ts b/packages/zod/src/v4/classic/tests/string.test.ts
index 1facb0d6..9d7fb775 100644
--- a/packages/zod/src/v4/classic/tests/string.test.ts
+++ b/packages/zod/src/v4/classic/tests/string.test.ts
@@ -1,3 +1,4 @@
+import { randomBytes } from "node:crypto";
 import { expect, test } from "vitest";
 
 import * as z from "zod/v4";
@@ -207,22 +208,22 @@ test("base64url validations", () => {
 
   const validBase64URLStrings = [
     "SGVsbG8gV29ybGQ", // "Hello World"
-    "SGVsbG8gV29ybGQ=", // "Hello World" with padding
+
     "VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw", // "This is an encoded string"
-    "VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw==", // "This is an encoded string" with padding
+
     "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcms", // "Many hands make light work"
-    "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcms=", // "Many hands make light work" with padding
+
     "UGF0aWVuY2UgaXMgdGhlIGtleSB0byBzdWNjZXNz", // "Patience is the key to success"
     "QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg", // "Base64 encoding is fun"
-    "QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg==", // "Base64 encoding is fun" with padding
+
     "MTIzNDU2Nzg5MA", // "1234567890"
-    "MTIzNDU2Nzg5MA==", // "1234567890" with padding
+
     "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo", // "abcdefghijklmnopqrstuvwxyz"
-    "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=", // "abcdefghijklmnopqrstuvwxyz with padding"
+
     "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo", // "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-    "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=", // "ABCDEFGHIJKLMNOPQRSTUVWXYZ" with padding
+
     "ISIkJSMmJyonKCk", // "!\"#$%&'()*"
-    "ISIkJSMmJyonKCk=", // "!\"#$%&'()*" with padding
+
     "", // Empty string is technically valid base64url
     "w7_Dv8O-w74K", // ÿÿþþ
     "123456",
@@ -239,6 +240,16 @@ test("base64url validations", () => {
     "!UGF0aWVuY2UgaXMgdGhlIGtleSB0byBzdWNjZXNz", // Invalid character '!'
     "?QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg==", // Invalid character '?'
     ".MTIzND2Nzg5MC4=", // Invalid character '.'
+
+    // disallow valid padding
+    "SGVsbG8gV29ybGQ=", // "Hello World" with padding
+    "VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw==", // "This is an encoded string" with padding
+    "TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcms=", // "Many hands make light work" with padding
+    "QmFzZTY0IGVuY29kaW5nIGlzIGZ1bg==", // "Base64 encoding is fun" with padding
+    "MTIzNDU2Nzg5MA==", // "1234567890" with padding
+    "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=", // "abcdefghijklmnopqrstuvwxyz with padding"
+    "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=", // "ABCDEFGHIJKLMNOPQRSTUVWXYZ" with padding
+    "ISIkJSMmJyonKCk=", // "!\"#$%&'()*" with padding
   ];
 
   for (const str of invalidBase64URLStrings) {
@@ -246,6 +257,13 @@ test("base64url validations", () => {
   }
 });
 
+test("big base64 and base64url", () => {
+  const bigbase64 = randomBytes(1024 * 1024 * 10).toString("base64");
+  z.base64().parse(bigbase64);
+  const bigbase64url = randomBytes(1024 * 1024 * 10).toString("base64url");
+  z.base64url().parse(bigbase64url);
+});
+
 test("jwt token", () => {
   const ONE_PART = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
   const NOT_BASE64 =
diff --git a/packages/zod/src/v4/mini/tests/error.test.ts b/packages/zod/src/v4/mini/tests/error.test.ts
index f4a5593e..d6267b73 100644
--- a/packages/zod/src/v4/mini/tests/error.test.ts
+++ b/packages/zod/src/v4/mini/tests/error.test.ts
@@ -7,3 +7,16 @@ test("no locale by default", () => {
   expect(result.error!.issues.length).toEqual(1);
   expect(result.error!.issues[0].message).toEqual("Invalid input");
 });
+
+test("error inheritance", () => {
+  const e1 = z.string().safeParse(123).error!;
+  expect(e1).toBeInstanceOf(z.core.$ZodError);
+  expect(e1).not.toBeInstanceOf(Error);
+
+  try {
+    z.string().parse(123);
+  } catch (e2) {
+    expect(e2).toBeInstanceOf(z.core.$ZodRealError);
+    expect(e2).toBeInstanceOf(Error);
+  }
+});