Repository: colinhacks/zod
Pull request #4374 (2025-05-15 16:30:18)

fix: use JSON.stringify to escape toDotPath keys w/ quotes
This should also correctly handle even weirder stuff like newlines in proeprty keys. JSON.stringify should do all the right escaping - if it's a valid JSON string, it's a valid key.

Note: one existing test was updated:

```ts
expect(z.core.toDotPath(["data[0]", "value"])).toMatchInlineSnapshot(`"data[0].value"`); // <- before
expect(z.core.toDotPath(["data[0]", "value"])).toMatchInlineSnapshot(`"["data[0]"].value"`); // <- after
```

This looks correct to me: Previously it was implying a shape of
`{data: [{value: '...'}]}` when actually it should be a shape of
`{'data[0]': {value: '...'}}`

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 -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<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=4374):

- 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/api.mdx b/packages/docs/content/api.mdx
index 578df4e5..866a5f65 100644
--- a/packages/docs/content/api.mdx
+++ b/packages/docs/content/api.mdx
@@ -311,7 +311,7 @@ schema.parse("sup"); // ❌
 To validate the hostname against a specific regex:
 
 ```ts
-const schema = z.url({ hostname: /^example.com$/ });
+const schema = z.url({ hostname: /^example\.com$/ });
 
 schema.parse("https://example.com"); // ✅
 schema.parse("https://zombo.com"); // ❌
@@ -1119,6 +1119,10 @@ type Category = z.infer<typeof Category>;
 // { name: string; subcategories: Category[] }
 ```
 
+<Callout type="warn"> 
+  Though recursive schemas are supported, passing cyclical data into Zod will cause an infinite loop.
+</Callout>
+
 You can also represent *mutually recursive types*:
 
 ```ts
@@ -1137,11 +1141,105 @@ const Post = z.object({
 });
 ```
 
-All object APIs (pick, omit, required, partial, etc) work as you'd expect.
+All object APIs (`.pick()`, `.omit()`, `.required()`, `.partial()`, etc.) work as you'd expect.
 
-<Callout type="warn"> 
-  Though recursive schemas are supported, passing cyclical data into Zod will cause an infinite loop.
-</Callout>
+Due to TypeScript limitations, recursive type inference can be finicky, and it only works in certain scenarios. Some more complicated types may trigger recursive type errors like this:
+
+```ts
+const Activity = z.object({
+  name: z.string(),
+  get subactivities() {
+    // ^ ❌ 'subactivities' implicitly has return type 'any' because it does not 
+    // // have a return type annotation and is referenced directly or indirectly 
+    // in one of its return expressions.ts(7023)
+
+    return z.union([z.null(), Activity]);
+  },
+});
+```
+
+In these cases, you can resolve the error with a type annotation on the offending getter:
+
+```ts
+const Activity = z.object({
+  name: z.string(),
+  get subactivities(): z.ZodUnion<[z.ZodNull, typeof Activity]> { // ✅
+    return z.union([z.null(), Activity]); 
+  },
+});
+```
+{/* 
+<Accordions>
+  <Accordion title="Resolving type errors in recursive schemas">
+    Recursive type inference can by mysterious. TypeScript is capable of it in certain limited scenarios. Depending on what you're trying to do, you may encounter errors like this:
+
+    ```ts
+    export const Activity = z.object({
+      name: z.string(),
+      get children() {
+        // ^ ❌ 'children' implicitly has return type 'any' because it does not 
+        // have a return type annotation and is referenced directly or indirectly 
+        // in one of its return expressions.ts(7023)
+
+        return z.optional(z.array(Activity)); //.optional();
+      },
+    });
+    ```
+
+    Here are a couple rules of thumb:
+
+    ### Object types only 
+    
+    Generally speaking, recursive inference only works with object types that are referencing each other. TypeScript has special handling for resolving getter-based recursive objects, which is what Zod relies on. If you try to add non-object types into the mix, you'll likely encounter errors.
+
+    ```ts
+    const Activity = z.object({
+      name: z.string(),
+      get children() { // ❌ type error
+        return z.optional(ActivityArray);
+      },
+    });
+
+    const ActivityArray = z.array(Activity);
+    ```
+
+    Sometimes you can get around this limitation by defining 
+
+
+    ### Avoid nesting function calls
+    
+    Functions like `z.array()` and `z.optional()` accept Zod schemas, so when you use them TypeScript will do some type-checking on their inputs to make sure they are valid. But type checking is the enemy of recursive type inference—it's hard for TypeScript to *check* and *infer* types at the same time. Methods do not have this problem, so prefer methods over functions when possible (sorry Zod Mini users).
+
+    ```ts
+    const Activity = z.object({
+      name: z.string(),
+      get subactivities() {
+        // ^ ❌ 'subactivities' implicitly has return type 'any' because it does not 
+        // // have a return type annotation and is referenced directly or indirectly 
+        // in one of its return expressions.ts(7023)
+
+        return z.union([z.null(), Activity]);
+      },
+    });
+    ```
+
+    ### Fall back to type annotations on your getters
+    
+    When in doubt, you can generally sidestep these issues with some carefully deployed type annotations on your getters. Due to the limitations described above, this is particularly necessary when using Zod Mini.
+
+    ```ts
+    import { z } from "zod/v4";
+
+    const Activity = z.object({
+      name: z.string(),
+      get subactivities(): z.ZodMiniDefault<z.ZodMiniArray<typeof Activity>> {
+        return z._default(z.array(Activity), []);
+      },
+    });
+    ```
+
+  </Accordion>
+</Accordions> */}
 
 ## Arrays
 
@@ -2064,6 +2162,33 @@ z.parse(randomDefault, undefined); // => 0.7223408162401552
 </Tab>
 </Tabs>
 
+
+## Prefaults
+
+In Zod, setting a *default* value will short-circuit the parsing process. If the input is `undefined`, the default value is eagerly returned. As such, the default value must be assignable to the *output type* of the schema.
+
+```ts
+const schema = z.string().transform(val => val.length).default(0);
+schema.parse(undefined); // => 0
+```
+
+Sometimes, it's useful to define a *prefault* ("pre-parse default") value. If the input is `undefined`, the prefault value will be parsed instead. The parsing process is *not* short circuited. As such, the prefault value must be assignable to the *input type* of the schema.
+
+```ts
+z.string().transform(val => val.length).prefault("tuna");
+schema.parse(undefined); // => 4
+```
+
+This is also useful if you want to pass some input value through some mutating refinements.
+
+```ts
+const a = z.string().trim().toUpperCase().prefault("  tuna  ");
+a.parse(undefined); // => "TUNA"
+
+const b = z.string().trim().toUpperCase().default("  tuna  ");
+b.parse(undefined); // => "  tuna  "
+```
+
 ## Catch
 
 Use `.catch()` to define a fallback value to be returned in the event of a validation error:
diff --git a/packages/docs/content/index.mdx b/packages/docs/content/index.mdx
index 6e3409a0..7403759c 100644
--- a/packages/docs/content/index.mdx
+++ b/packages/docs/content/index.mdx
@@ -111,26 +111,6 @@ console.log(data.name);
 - Extensive ecosystem
 
 
-
-## Requirements
-
-
-Zod is tested against *TypeScript v5.5* and later. Older versions may work but are not officially supported.
-
-You must enable `strict` mode in your `tsconfig.json`. This is a best practice for all TypeScript projects.
-
-  
-  ```ts
-  // tsconfig.json
-  {
-    // ...
-    "compilerOptions": {
-      // ...
-      "strict": true
-    }
-  }
-  ```
-
 ## Installation
 
 {/* ### `npm` */}
@@ -155,6 +135,29 @@ pnpm add zod@canary          # pnpm
 
 {/* > The rest of this README assumes you are using npm and importing directly from the `"zod"` package. */}
 
+## Requirements
+
+Zod is tested against *TypeScript v5.5* and later. Older versions may work but are not officially supported.
+
+You must enable `strict` mode in your `tsconfig.json`. This is a best practice for all TypeScript projects.
+  
+```ts
+// tsconfig.json
+{
+  // ...
+  "compilerOptions": {
+    // ...
+    "strict": true
+  }
+}
+```
+
+The legacy `"moduleResolution": "node"` and `"moduleResolution": "classic"` modes are not supported. Your `"moduleResolution"` should be set to one of the following:
+
+- `"node16"` (default if `"module"` is set to `"node16"`/`"node18"`)
+- `"nodenext"` (default if `"module"` is set to `"nodenext"`)
+- `"bundler"`
+
 ## Sponsors
 
 Sponsorship at any level is appreciated and encouraged. If you built a paid product using Zod, consider one of the [corporate tiers](https://github.com/sponsors/colinhacks).
diff --git a/packages/docs/content/json-schema.mdx b/packages/docs/content/json-schema.mdx
index 88674355..94298d72 100644
--- a/packages/docs/content/json-schema.mdx
+++ b/packages/docs/content/json-schema.mdx
@@ -29,7 +29,7 @@ z.toJSONSchema(schema)
 // }
 ```
 
-All schema & checks are converted to their closest JSON Schema equivalent. Some types have no analog and cannot be reasonably represented. See the [`unrepresentable'](#unrepresentable) section below for more information on handling these cases.
+All schema & checks are converted to their closest JSON Schema equivalent. Some types have no analog and cannot be reasonably represented. See the [`unrepresentable`](#unrepresentable) section below for more information on handling these cases.
 
 ```ts
 z.bigint(); // ❌
diff --git a/packages/docs/content/v4/changelog.mdx b/packages/docs/content/v4/changelog.mdx
index cadcda1a..d2723b53 100644
--- a/packages/docs/content/v4/changelog.mdx
+++ b/packages/docs/content/v4/changelog.mdx
@@ -108,28 +108,33 @@ z.string({
 </Tab>
 </Tabs>
 
-## `ZodError`
+## `.safeParse()` 
+
+For performance reasons, the errors returned by `.safeParse()` and `.safeParseAsync()` no longer extend `Error`. 
+
+```ts
+const result = z.string().safeParse(12); 
+result.error! instanceof Error; // => false
+```
 
-### no longer extends `Error`
+It is very slow to instantiate `Error` instances in JavaScript, as the initialization process snapshots the call stack. In the case of Zod's "safe" parse methods, it's expected that you will handle errors at the point of parsing, so instantiating a true `Error` object adds little value anyway. 
 
-It is very slow to instantiate `Error` instances in JavaScript, as the initialization process snapshots the call stack. The magnitude of this performance hit is too much to justify, and extending `Error` adds little value anyway. The `.stack` trace includes lots of Zod internals and can be confusing. 
+> Pro tip: prefer `.safeParse()` over `try/catch` in performance-sensitive code.
 
-In Zod 4 the `ZodError` class no longer extends the plain JavaScript `Error` class. Instead, `ZodError` `implements` the `Error` interface. This means all error-handling code should still work with the exception of `instanceof Error` checks. 
+By contrast the errors thrown by `.parse()` and `.parseAsync()` still `Error`. 
 
 ```ts
 try {
-  z.string().parse(data)
-} catch(err) {
-  if (err instanceof z.ZodError) {
-    // handle ZodError
-  }
-  
-  if (err instanceof Error) {
-    // handle regular Error
-  }
+  z.string().parse(12);
+} catch (err) {
+  console.log(err instanceof Error); // => true
 }
 ```
 
+Aside from the prototype difference, the error classes are identical.
+
+## `ZodError`
+
 ### updates issue formats
 
 The issue formats have been dramatically streamlined. 
@@ -241,10 +246,13 @@ z.object({ a: z.string() }).extend(z.object({ b: z.number() })); // ✅
 
 `POSITIVE_INFINITY` and `NEGATIVE_INFINITY` are no longer considered valid values for `z.number()`.
 
-### `.int()` accepts safe integers only
+### `.safe()` no longer accepts floats
+
+In Zod 3, `z.number().safe()` is deprecated. It now behaves identically to `.int()` (see below). Importantly, that means it no longer accepts floats.
 
-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.
+### `.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
 
@@ -280,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.
@@ -475,6 +488,8 @@ myFunction.implement((input) => {
 </Tab>
 </Tabs>
 
+If you have a desperate need for a Zod schema with a function type, consider [this workaround](https://github.com/colinhacks/zod/issues/4143#issuecomment-2845134912).
+
 ### adds `.implementAsync()`
 
 To define an async function, use `implementAsync()` instead of `implement()`. 
diff --git a/packages/zod/src/v4/classic/coerce.ts b/packages/zod/src/v4/classic/coerce.ts
index 9ccc2f58..c5cf0c62 100644
--- a/packages/zod/src/v4/classic/coerce.ts
+++ b/packages/zod/src/v4/classic/coerce.ts
@@ -1,27 +1,27 @@
 import * as core from "zod/v4/core";
 import * as schemas from "./schemas.js";
 
-export interface ZodCoercedString extends schemas._ZodString<unknown> {}
-export function string(params?: string | core.$ZodStringParams): ZodCoercedString {
-  return core._coercedString(schemas.ZodString, params);
+export interface ZodCoercedString<T = unknown> extends schemas._ZodString<T> {}
+export function string<T = unknown>(params?: string | core.$ZodStringParams): ZodCoercedString<T> {
+  return core._coercedString(schemas.ZodString, params) as any;
 }
 
-export interface ZodCoercedNumber extends schemas._ZodNumber<unknown> {}
-export function number(params?: string | core.$ZodNumberParams): ZodCoercedNumber {
-  return core._coercedNumber(schemas.ZodNumber, params);
+export interface ZodCoercedNumber<T = unknown> extends schemas._ZodNumber<T> {}
+export function number<T = unknown>(params?: string | core.$ZodNumberParams): ZodCoercedNumber<T> {
+  return core._coercedNumber(schemas.ZodNumber, params) as ZodCoercedNumber<T>;
 }
 
-export interface ZodCoercedBoolean extends schemas._ZodBoolean<unknown> {}
-export function boolean(params?: string | core.$ZodBooleanParams): ZodCoercedBoolean {
-  return core._coercedBoolean(schemas.ZodBoolean, params);
+export interface ZodCoercedBoolean<T = unknown> extends schemas._ZodBoolean<T> {}
+export function boolean<T = unknown>(params?: string | core.$ZodBooleanParams): ZodCoercedBoolean<T> {
+  return core._coercedBoolean(schemas.ZodBoolean, params) as ZodCoercedBoolean<T>;
 }
 
-export interface ZodCoercedBigInt extends schemas._ZodBigInt<unknown> {}
-export function bigint(params?: string | core.$ZodBigIntParams): ZodCoercedBigInt {
-  return core._coercedBigint(schemas.ZodBigInt, params);
+export interface ZodCoercedBigInt<T = unknown> extends schemas._ZodBigInt<T> {}
+export function bigint<T = unknown>(params?: string | core.$ZodBigIntParams): ZodCoercedBigInt<T> {
+  return core._coercedBigint(schemas.ZodBigInt, params) as ZodCoercedBigInt<T>;
 }
 
-export interface ZodCoercedDate extends schemas._ZodDate<unknown> {}
-export function date(params?: string | core.$ZodDateParams): ZodCoercedDate {
-  return core._coercedDate(schemas.ZodDate, params);
+export interface ZodCoercedDate<T = unknown> extends schemas._ZodDate<T> {}
+export function date<T = unknown>(params?: string | core.$ZodDateParams): ZodCoercedDate<T> {
+  return core._coercedDate(schemas.ZodDate, params) as ZodCoercedDate<T>;
 }
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/external.ts b/packages/zod/src/v4/classic/external.ts
index 2d30ff89..bb45c220 100644
--- a/packages/zod/src/v4/classic/external.ts
+++ b/packages/zod/src/v4/classic/external.ts
@@ -24,6 +24,8 @@ export {
   regexes,
   treeifyError,
   prettifyError,
+  formatError,
+  flattenError,
   toJSONSchema,
   locales,
 } from "zod/v4/core";
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 b1e05b2e..a1a0d001 100644
--- a/packages/zod/src/v4/classic/schemas.ts
+++ b/packages/zod/src/v4/classic/schemas.ts
@@ -70,6 +70,8 @@ export interface ZodType<out Output = unknown, out Input = unknown> extends core
   nullish(): ZodOptional<ZodNullable<this>>;
   default(def: util.NoUndefined<core.output<this>>): ZodDefault<this>;
   default(def: () => util.NoUndefined<core.output<this>>): ZodDefault<this>;
+  prefault(def: () => core.input<this>): ZodPrefault<this>;
+  prefault(def: core.input<this>): ZodPrefault<this>;
   array(): ZodArray<this>;
   or<T extends core.$ZodType>(option: T): ZodUnion<[this, T]>;
   and<T extends core.$ZodType>(incoming: T): ZodIntersection<this, T>;
@@ -92,7 +94,22 @@ export interface ZodType<out Output = unknown, out Input = unknown> extends core
   meta(data: core.$replace<core.GlobalMeta, this>): this;
 
   // helpers
+  /** @deprecated Try safe-parsing `undefined` (this is what `isOptional` does internally):
+   *
+   * ```ts
+   * const schema = z.string().optional();
+   * const isOptional = schema.safeParse(undefined).success; // true
+   * ```
+   */
   isOptional(): boolean;
+  /**
+   * @deprecated Try safe-parsing `null` (this is what `isNullable` does internally):
+   *
+   * ```ts
+   * const schema = z.string().nullable();
+   * const isNullable = schema.safeParse(null).success; // true
+   * ```
+   */
   isNullable(): boolean;
 }
 
@@ -166,6 +183,7 @@ export const ZodType: core.$constructor<ZodType> = /*@__PURE__*/ core.$construct
   inst.and = (arg) => intersection(inst, arg);
   inst.transform = (tx) => pipe(inst, transform(tx as any)) as never;
   inst.default = (def) => _default(inst, def);
+  inst.prefault = (def) => prefault(inst, def);
   // inst.coalesce = (def, params) => coalesce(inst, def, params);
   inst.catch = (params) => _catch(inst, params);
   inst.pipe = (target) => pipe(inst, target);
@@ -1026,8 +1044,7 @@ export const ZodArray: core.$constructor<ZodArray> = /*@__PURE__*/ core.$constru
   inst.length = (len, params) => inst.check(checks.length(len, params));
 });
 
-export function array<T extends core.$ZodType>(element: T, params?: string | core.$ZodArrayParams): ZodArray<T>;
-export function array<T extends core.$ZodType>(element: core.$ZodType, params?: any): ZodArray<T> {
+export function array<T extends core.$ZodType>(element: T, params?: string | core.$ZodArrayParams): ZodArray<T> {
   return core._array(ZodArray, element, params) as any;
 }
 
@@ -1038,37 +1055,33 @@ export function keyof<T extends ZodObject>(schema: T): ZodLiteral<keyof T["_zod"
 }
 
 // ZodObject
+
 export interface ZodObject<
   // @ts-ignore cast variance
   out Shape extends core.$ZodShape = core.$ZodLooseShape,
-  OutExtra extends Record<string, unknown> = Record<string, unknown>,
-  InExtra extends Record<string, unknown> = Record<string, unknown>,
+  out Config extends core.$ZodObjectConfig = core.$ZodObjectConfig,
 > extends ZodType {
-  _zod: core.$ZodObjectInternals<Shape, OutExtra, InExtra>;
+  _zod: core.$ZodObjectInternals<Shape, Config>;
   shape: Shape;
 
   keyof(): ZodEnum<util.ToEnum<keyof Shape & string>>;
   /** Define a schema to validate all unrecognized keys. This overrides the existing strict/loose behavior. */
-  catchall<T extends core.$ZodType>(schema: T): ZodObject<Shape, Record<string, T["_zod"]["output"]>>;
+  catchall<T extends core.$ZodType>(schema: T): ZodObject<Shape, core.$catchall<T>>;
 
   /** @deprecated Use `z.looseObject()` or `.loose()` instead. */
-  passthrough(): ZodObject<Shape, Record<string, unknown>>;
+  passthrough(): ZodObject<Shape, core.$loose>;
   /** Consider `z.looseObject(A.shape)` instead */
-  loose(): ZodObject<Shape, Record<string, unknown>>;
+  loose(): ZodObject<Shape, core.$loose>;
 
   /** Consider `z.strictObject(A.shape)` instead */
-  strict(): ZodObject<Shape, {}>;
+  strict(): ZodObject<Shape, core.$strict>;
 
   /** This is the default behavior. This method call is likely unnecessary. */
-  strip(): ZodObject<Shape, {}>;
+  strip(): ZodObject<Shape, core.$strict>;
 
   extend<U extends core.$ZodLooseShape & Partial<Record<keyof Shape, core.$ZodType>>>(
     shape: U
-  ): ZodObject<
-    util.Extend<Shape, U>,
-    OutExtra,
-    InExtra // & B['_zod']["extra"]
-  >;
+  ): ZodObject<util.Extend<Shape, U>, Config>;
 
   /**
    * @deprecated Use destructuring to merge the shapes:
@@ -1080,24 +1093,21 @@ export interface ZodObject<
    * });
    * ```
    */
-  merge<U extends ZodObject>(
-    other: U
-  ): ZodObject<util.Extend<Shape, U["shape"]>, U["_zod"]["outextra"], U["_zod"]["inextra"]>;
+  merge<U extends ZodObject>(other: U): ZodObject<util.Extend<Shape, U["shape"]>, U["_zod"]["config"]>;
 
   pick<M extends util.Exactly<util.Mask<keyof Shape>, M>>(
     mask: M
-  ): ZodObject<util.Flatten<Pick<Shape, Extract<keyof Shape, keyof M>>>, OutExtra, InExtra>;
+  ): ZodObject<util.Flatten<Pick<Shape, Extract<keyof Shape, keyof M>>>, Config>;
 
   omit<M extends util.Exactly<util.Mask<keyof Shape>, M>>(
     mask: M
-  ): ZodObject<util.Flatten<Omit<Shape, Extract<keyof Shape, keyof M>>>, OutExtra, InExtra>;
+  ): ZodObject<util.Flatten<Omit<Shape, Extract<keyof Shape, keyof M>>>, Config>;
 
   partial(): ZodObject<
     {
       [k in keyof Shape]: ZodOptional<Shape[k]>;
     },
-    OutExtra,
-    InExtra
+    Config
   >;
   partial<M extends util.Exactly<util.Mask<keyof Shape>, M>>(
     mask: M
@@ -1105,8 +1115,7 @@ export interface ZodObject<
     {
       [k in keyof Shape]: k extends keyof M ? ZodOptional<Shape[k]> : Shape[k];
     },
-    OutExtra,
-    InExtra
+    Config
   >;
 
   // required
@@ -1114,8 +1123,7 @@ export interface ZodObject<
     {
       [k in keyof Shape]: ZodNonOptional<Shape[k]>;
     },
-    OutExtra,
-    InExtra
+    Config
   >;
   required<M extends util.Exactly<util.Mask<keyof Shape>, M>>(
     mask: M
@@ -1123,8 +1131,7 @@ export interface ZodObject<
     {
       [k in keyof Shape]: k extends keyof M ? ZodNonOptional<Shape[k]> : Shape[k];
     },
-    OutExtra,
-    InExtra
+    Config
   >;
 }
 
@@ -1156,7 +1163,7 @@ export const ZodObject: core.$constructor<ZodObject> = /*@__PURE__*/ core.$const
 export function object<T extends core.$ZodLooseShape = Partial<Record<never, core.$ZodType>>>(
   shape?: T,
   params?: string | core.$ZodObjectParams
-): ZodObject<util.Writeable<T> & {}, {}, {}> {
+): ZodObject<util.Writeable<T> & {}, core.$strip> {
   const def: core.$ZodObjectDef = {
     type: "object",
 
@@ -1175,7 +1182,7 @@ export function object<T extends core.$ZodLooseShape = Partial<Record<never, cor
 export function strictObject<T extends core.$ZodLooseShape>(
   shape: T,
   params?: string | core.$ZodObjectParams
-): ZodObject<T, {}, {}> {
+): ZodObject<T, core.$strict> {
   return new ZodObject({
     type: "object",
 
@@ -1190,10 +1197,11 @@ export function strictObject<T extends core.$ZodLooseShape>(
 }
 
 // looseObject
+
 export function looseObject<T extends core.$ZodLooseShape>(
   shape: T,
   params?: string | core.$ZodObjectParams
-): ZodObject<T, { [k: string]: unknown }, { [k: string]: unknown }> {
+): ZodObject<T, core.$loose> {
   return new ZodObject({
     type: "object",
 
@@ -1596,7 +1604,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));
         }
       };
@@ -1615,13 +1623,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;
 }
 
@@ -1698,11 +1704,40 @@ export function _default<T extends core.$ZodType>(
 ): ZodDefault<T> {
   return new ZodDefault({
     type: "default",
-    defaultValue: (typeof defaultValue === "function" ? defaultValue : () => defaultValue) as () => core.output<T>,
     innerType,
+    get defaultValue() {
+      return typeof defaultValue === "function" ? (defaultValue as Function)() : defaultValue;
+    },
   }) as any as ZodDefault<T>;
 }
 
+// ZodPrefault
+export interface ZodPrefault<T extends core.$ZodType = core.$ZodType> extends ZodType {
+  _zod: core.$ZodPrefaultInternals<T>;
+  unwrap(): T;
+}
+export const ZodPrefault: core.$constructor<ZodPrefault> = /*@__PURE__*/ core.$constructor(
+  "ZodPrefault",
+  (inst, def) => {
+    core.$ZodPrefault.init(inst, def);
+    ZodType.init(inst, def);
+    inst.unwrap = () => inst._zod.def.innerType;
+  }
+);
+
+export function prefault<T extends core.$ZodType>(
+  innerType: T,
+  defaultValue: core.input<T> | (() => core.input<T>)
+): ZodPrefault<T> {
+  return new ZodPrefault({
+    type: "prefault",
+    innerType,
+    get defaultValue() {
+      return typeof defaultValue === "function" ? (defaultValue as Function)() : defaultValue;
+    },
+  }) as ZodPrefault<T>;
+}
+
 // ZodNonOptional
 export interface ZodNonOptional<T extends core.$ZodType = core.$ZodType> extends ZodType {
   _zod: core.$ZodNonOptionalInternals<T>;
@@ -1965,16 +2000,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}`,
@@ -2017,13 +2048,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 996beb97..663397f8 100644
--- a/packages/zod/src/v4/core/api.ts
+++ b/packages/zod/src/v4/core/api.ts
@@ -988,7 +988,7 @@ export type $ZodArrayParams = util.TypeParams<schemas.$ZodArray, "element">;
 export function _array<T extends schemas.$ZodType>(
   Class: util.SchemaClass<schemas.$ZodArray>,
   element: T,
-  params?: $ZodArrayParams
+  params?: string | $ZodArrayParams
 ): schemas.$ZodArray<T> {
   return new Class({
     type: "array",
@@ -1007,7 +1007,7 @@ export type $ZodUnionParams = util.TypeParams<schemas.$ZodUnion, "options">;
 export function _union<const T extends readonly schemas.$ZodObject[]>(
   Class: util.SchemaClass<schemas.$ZodUnion>,
   options: T,
-  params?: $ZodUnionParams
+  params?: string | $ZodUnionParams
 ): schemas.$ZodUnion<T> {
   return new Class({
     type: "union",
@@ -1028,7 +1028,7 @@ export type $ZodDiscriminatedUnionParams = util.TypeParams<schemas.$ZodDiscrimin
 export function _discriminatedUnion<Types extends [$ZodTypeDiscriminable, ...$ZodTypeDiscriminable[]]>(
   Class: util.SchemaClass<schemas.$ZodDiscriminatedUnion>,
   options: Types,
-  params?: $ZodDiscriminatedUnionParams
+  params?: string | $ZodDiscriminatedUnionParams
 ): schemas.$ZodDiscriminatedUnion<Types> {
   return new Class({
     type: "union",
@@ -1056,24 +1056,24 @@ export type $ZodTupleParams = util.TypeParams<schemas.$ZodTuple, "items" | "rest
 export function _tuple<T extends readonly [schemas.$ZodType, ...schemas.$ZodType[]]>(
   Class: util.SchemaClass<schemas.$ZodTuple>,
   items: T,
-  params?: $ZodTupleParams
+  params?: string | $ZodTupleParams
 ): schemas.$ZodTuple<T, null>;
 export function _tuple<T extends readonly [schemas.$ZodType, ...schemas.$ZodType[]], Rest extends schemas.$ZodType>(
   Class: util.SchemaClass<schemas.$ZodTuple>,
   items: T,
   rest: Rest,
-  params?: $ZodTupleParams
+  params?: string | $ZodTupleParams
 ): schemas.$ZodTuple<T, Rest>;
 // export function _tuple(
 //   Class: util.SchemaClass<schemas.$ZodTuple>,
 //   items: [],
-//   params?: $ZodTupleParams
+//   params?: string | $ZodTupleParams
 // ): schemas.$ZodTuple<[], null>;
 export function _tuple(
   Class: util.SchemaClass<schemas.$ZodTuple>,
   items: schemas.$ZodType[],
-  _paramsOrRest?: $ZodTupleParams | schemas.$ZodType,
-  _params?: $ZodTupleParams
+  _paramsOrRest?: string | $ZodTupleParams | schemas.$ZodType,
+  _params?: string | $ZodTupleParams
 ) {
   const hasRest = _paramsOrRest instanceof schemas.$ZodType;
   const params = hasRest ? _params : _paramsOrRest;
@@ -1092,7 +1092,7 @@ export function _record<Key extends schemas.$ZodRecordKey, Value extends schemas
   Class: util.SchemaClass<schemas.$ZodRecord>,
   keyType: Key,
   valueType: Value,
-  params?: $ZodRecordParams
+  params?: string | $ZodRecordParams
 ): schemas.$ZodRecord<Key, Value> {
   return new Class({
     type: "record",
@@ -1108,7 +1108,7 @@ export function _map<Key extends schemas.$ZodObject, Value extends schemas.$ZodO
   Class: util.SchemaClass<schemas.$ZodMap>,
   keyType: Key,
   valueType: Value,
-  params?: $ZodMapParams
+  params?: string | $ZodMapParams
 ): schemas.$ZodMap<Key, Value> {
   return new Class({
     type: "map",
@@ -1123,7 +1123,7 @@ export type $ZodSetParams = util.TypeParams<schemas.$ZodSet, "valueType">;
 export function _set<Value extends schemas.$ZodObject>(
   Class: util.SchemaClass<schemas.$ZodSet>,
   valueType: Value,
-  params?: $ZodSetParams
+  params?: string | $ZodSetParams
 ): schemas.$ZodSet<Value> {
   return new Class({
     type: "set",
@@ -1137,14 +1137,14 @@ export type $ZodEnumParams = util.TypeParams<schemas.$ZodEnum, "entries">;
 export function _enum<const T extends string[]>(
   Class: util.SchemaClass<schemas.$ZodEnum>,
   values: T,
-  params?: $ZodEnumParams
+  params?: string | $ZodEnumParams
 ): schemas.$ZodEnum<util.ToEnum<T[number]>>;
 export function _enum<T extends util.EnumLike>(
   Class: util.SchemaClass<schemas.$ZodEnum>,
   entries: T,
-  params?: $ZodEnumParams
+  params?: string | $ZodEnumParams
 ): schemas.$ZodEnum<T>;
-export function _enum(Class: util.SchemaClass<schemas.$ZodEnum>, values: any, params?: $ZodEnumParams) {
+export function _enum(Class: util.SchemaClass<schemas.$ZodEnum>, values: any, params?: string | $ZodEnumParams) {
   const entries: any = Array.isArray(values) ? Object.fromEntries(values.map((v) => [v, v])) : values;
   // if (Array.isArray(values)) {
   //   for (const value of values) {
@@ -1175,7 +1175,7 @@ export function _enum(Class: util.SchemaClass<schemas.$ZodEnum>, values: any, pa
 export function _nativeEnum<T extends util.EnumLike>(
   Class: util.SchemaClass<schemas.$ZodEnum>,
   entries: T,
-  params?: $ZodEnumParams
+  params?: string | $ZodEnumParams
 ): schemas.$ZodEnum<T> {
   return new Class({
     type: "enum",
@@ -1189,12 +1189,12 @@ export type $ZodLiteralParams = util.TypeParams<schemas.$ZodLiteral, "values">;
 export function _literal<const T extends Array<util.Literal>>(
   Class: util.SchemaClass<schemas.$ZodLiteral>,
   value: T,
-  params?: $ZodLiteralParams
+  params?: string | $ZodLiteralParams
 ): schemas.$ZodLiteral<T[number]>;
 export function _literal<const T extends util.Literal>(
   Class: util.SchemaClass<schemas.$ZodLiteral>,
   value: T,
-  params?: $ZodLiteralParams
+  params?: string | $ZodLiteralParams
 ): schemas.$ZodLiteral<T>;
 export function _literal(Class: util.SchemaClass<schemas.$ZodLiteral>, value: any, params: any) {
   return new Class({
@@ -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?: $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;
 }
 
@@ -1260,8 +1258,10 @@ export function _default<T extends schemas.$ZodObject>(
 ): schemas.$ZodDefault<T> {
   return new Class({
     type: "default",
-    defaultValue: (typeof defaultValue === "function" ? defaultValue : () => defaultValue) as any,
     innerType,
+    get defaultValue() {
+      return typeof defaultValue === "function" ? (defaultValue as Function)() : defaultValue;
+    },
   }) as any;
 }
 
@@ -1270,7 +1270,7 @@ export type $ZodNonOptionalParams = util.TypeParams<schemas.$ZodNonOptional, "in
 export function _nonoptional<T extends schemas.$ZodObject>(
   Class: util.SchemaClass<schemas.$ZodNonOptional>,
   innerType: T,
-  params?: $ZodNonOptionalParams
+  params?: string | $ZodNonOptionalParams
 ): schemas.$ZodNonOptional<T> {
   return new Class({
     type: "nonoptional",
@@ -1339,7 +1339,7 @@ export type $ZodTemplateLiteralParams = util.TypeParams<schemas.$ZodTemplateLite
 export function _templateLiteral<const Parts extends schemas.$TemplateLiteralPart[]>(
   Class: util.SchemaClass<schemas.$ZodTemplateLiteral>,
   parts: Parts,
-  params?: $ZodTemplateLiteralParams
+  params?: string | $ZodTemplateLiteralParams
 ): schemas.$ZodTemplateLiteral<schemas.$PartsToTemplateLiteral<Parts>> {
   return new Class({
     type: "template_literal",
@@ -1419,7 +1419,7 @@ export function _stringbool(
     Boolean?: typeof schemas.$ZodBoolean;
     Unknown?: typeof schemas.$ZodUnknown;
   },
-  _params?: $ZodStringBoolParams
+  _params?: string | $ZodStringBoolParams
 ): schemas.$ZodPipe<schemas.$ZodUnknown, schemas.$ZodBoolean<boolean>> {
   const params = util.normalizeParams(_params);
   const trueValues = new Set(params?.truthy ?? ["true", "1", "yes", "on", "y", "enabled"]);
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/doc.ts b/packages/zod/src/v4/core/doc.ts
index ffb7bd72..55e7c4fb 100644
--- a/packages/zod/src/v4/core/doc.ts
+++ b/packages/zod/src/v4/core/doc.ts
@@ -34,9 +34,10 @@ export class Doc {
   }
 
   compile() {
+    const F = Function;
     const args = this?.args;
     const content = this?.content ?? [``];
     const lines = [...content.map((x) => `  ${x}`)];
-    return new Function(...args, lines.join("\n"));
+    return new F(...args, lines.join("\n"));
   }
 }
diff --git a/packages/zod/src/v4/core/errors.ts b/packages/zod/src/v4/core/errors.ts
index 84d48601..0235088e 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   ////////////////////////
 
@@ -274,9 +248,7 @@ export type $ZodFormattedError<T, U = string> = {
   _errors: U[];
 } & util.Flatten<_ZodFormattedError<T, U>>;
 
-/** @deprecated Use `z.treeifyError()` instead. */
 export function formatError<T>(error: $ZodError<T>): $ZodFormattedError<T>;
-/** @deprecated Use `z.treeifyError()` instead. */
 export function formatError<T, U>(error: $ZodError<T>, mapper?: (issue: $ZodIssue) => U): $ZodFormattedError<T, U>;
 export function formatError<T>(error: $ZodError, _mapper?: any) {
   const mapper: (issue: $ZodIssue) => any =
@@ -319,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[]
@@ -354,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: [] };
@@ -385,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++;
         }
       }
@@ -451,8 +388,8 @@ export function toDotPath(path: (string | number | symbol)[]): string {
   const segs: string[] = [];
   for (const seg of path) {
     if (typeof seg === "number") segs.push(`[${seg}]`);
-    else if (typeof seg === "symbol") segs.push(`["${String(seg)}"]`);
-    else if (seg.includes(".")) segs.push(`["${seg}"]`);
+    else if (typeof seg === "symbol") segs.push(`[${JSON.stringify(String(seg))}]`);
+    else if (/[^\w$]/.test(seg)) segs.push(`[${JSON.stringify(seg)}]`);
     else {
       if (segs.length) segs.push(".");
       segs.push(seg);
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 b29b8cbf..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,
@@ -57,7 +57,7 @@ export type $SafeParse = <T extends schemas.$ZodType>(
 ) => util.SafeParseResult<core.output<T>>;
 
 export const _safeParse: (_Err: $ZodErrorClass) => $SafeParse = (_Err) => (schema, value, _ctx) => {
-  const ctx: schemas.ParseContextInternal = _ctx ? Object.assign(_ctx, { async: false }) : { async: false };
+  const ctx: schemas.ParseContextInternal = _ctx ? { ..._ctx, async: false } : { async: false };
   const result = schema._zod.run({ value, issues: [] }, ctx);
   if (result instanceof Promise) {
     throw new core.$ZodAsyncError();
@@ -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 c036c773..34acf032 100644
--- a/packages/zod/src/v4/core/schemas.ts
+++ b/packages/zod/src/v4/core/schemas.ts
@@ -2,6 +2,7 @@ import * as checks from "./checks.js";
 import * as core from "./core.js";
 import { Doc } from "./doc.js";
 import type * as errors from "./errors.js";
+import { safeParse, safeParseAsync } from "./parse.js";
 import * as regexes from "./regexes.js";
 import type { StandardSchemaV1 } from "./standard-schema.js";
 import * as util from "./util.js";
@@ -15,7 +16,7 @@ export interface ParseContext<T extends errors.$ZodIssueBase = never> {
   /** Include the `input` field in issue objects. Default `false`. */
   readonly reportInput?: boolean;
   /** Skip eval-based fast path. Default `false`. */
-  readonly noPrecompilation?: boolean;
+  readonly jitless?: boolean;
   /** Abort validation after the first error. Default `false`. */
   // readonly abortEarly?: boolean;
 }
@@ -67,6 +68,7 @@ export interface $ZodTypeDef {
     | "success"
     | "transform"
     | "default"
+    | "prefault"
     | "catch"
     | "nan"
     | "pipe"
@@ -79,11 +81,6 @@ export interface $ZodTypeDef {
   checks?: checks.$ZodCheck<never>[];
 }
 
-export const $out: unique symbol = Symbol("out");
-export type $out = typeof $out;
-export const $in: unique symbol = Symbol("in");
-export type $in = typeof $in;
-
 // @ts-ignore
 export interface $ZodTypeInternals<out O = unknown, out I = unknown> {
   /** The `@zod/core` version of this schema */
@@ -258,19 +255,12 @@ export const $ZodType: core.$constructor<$ZodType> = /*@__PURE__*/ core.$constru
 
   inst["~standard"] = {
     validate: (value: unknown) => {
-      const result = inst._zod.run({ value, issues: [] }, {});
-      if (result instanceof Promise) {
-        return result.then(({ issues, value }) => {
-          if (issues.length === 0) return { value } as any;
-          return {
-            issues: issues.map((iss) => util.finalizeIssue(iss, {}, core.config())),
-          };
-        });
+      try {
+        const r = safeParse(inst, value);
+        return r.success ? { value: r.data } : { issues: r.error?.issues };
+      } catch (_) {
+        return safeParseAsync(inst, value).then((r) => (r.success ? { value: r.data } : { issues: r.error?.issues }));
       }
-      if (result.issues.length === 0) return { value: result.value } as any;
-      return {
-        issues: result.issues.map((iss) => util.finalizeIssue(iss, {}, core.config())),
-      };
     },
     vendor: "zod",
     version: 1 as const,
@@ -820,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"> {}
@@ -837,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"> {}
@@ -858,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,
+      });
+    };
   }
 );
 
@@ -1537,20 +1565,18 @@ export interface $ZodObjectDef<Shape extends $ZodShape = $ZodShape> extends $Zod
 export interface $ZodObjectInternals<
   // @ts-ignore Cast variance
   out Shape extends Readonly<$ZodShape> = Readonly<$ZodShape>,
-  out OutExtra extends Record<string, unknown> = Record<string, unknown>,
-  out InExtra extends Record<string, unknown> = Record<string, unknown>,
+  out Config extends $ZodObjectConfig = $ZodObjectConfig,
 > extends $ZodTypeInternals<any, any> {
   def: $ZodObjectDef<Shape>;
-  outextra: OutExtra;
-  inextra: InExtra;
+  config: Config;
   isst: errors.$ZodIssueInvalidType | errors.$ZodIssueUnrecognizedKeys;
   disc: util.DiscriminatorMap;
 
   // special keys only used for objects
   // not defined on $ZodTypeInternals (base interface) because it breaks cyclical inference
   // the z.infer<> util checks for these first when extracting inferred type
-  "~output": $InferObjectOutput<Shape, OutExtra>;
-  "~input": $InferObjectInput<Shape, InExtra>;
+  "~output": $InferObjectOutput<Shape, Config["out"]>;
+  "~input": $InferObjectInput<Shape, Config["in"]>;
 }
 export type $ZodLooseShape = Record<string, any>;
 
@@ -1559,26 +1585,25 @@ type OptionalInSchema = { _zod: { optionality: "defaulted" | "optional" } };
 
 export type $InferObjectOutput<T extends $ZodLooseShape, Extra extends Record<string, unknown>> = string extends keyof T
   ? object
-  : keyof T extends never
+  : keyof (T & Extra) extends never
     ? Record<string, never>
     : util.Prettify<
         {
           -readonly [k in keyof T as T[k] extends OptionalOutSchema ? never : k]: core.output<T[k]>;
         } & {
           -readonly [k in keyof T as T[k] extends OptionalOutSchema ? k : never]?: core.output<T[k]>;
-        }
-      > &
-        Extra;
+        } & Extra
+      >;
 
 export type $InferObjectInput<T extends $ZodLooseShape, Extra extends Record<string, unknown>> = string extends keyof T
   ? object
-  : keyof T extends never
+  : keyof (T & Extra) extends never
     ? Record<string, never>
     : util.Prettify<
         {
-          [k in keyof T as T[k] extends OptionalInSchema ? never : k]: core.input<T[k]>;
+          -readonly [k in keyof T as T[k] extends OptionalInSchema ? never : k]: core.input<T[k]>;
         } & {
-          [k in keyof T as T[k] extends OptionalInSchema ? k : never]?: core.input<T[k]>;
+          -readonly [k in keyof T as T[k] extends OptionalInSchema ? k : never]?: core.input<T[k]>;
         } & Extra
       >;
 
@@ -1586,9 +1611,9 @@ function handleObjectResult(result: ParsePayload, final: ParsePayload, key: Prop
   // if(isOptional)
   if (result.issues.length) {
     final.issues.push(...util.prefixIssues(key, result.issues));
-  } else {
-    (final.value as any)[key] = result.value;
   }
+
+  (final.value as any)[key] = result.value;
 }
 
 function handleOptionalObjectResult(result: ParsePayload, final: ParsePayload, key: PropertyKey, input: any) {
@@ -1598,6 +1623,8 @@ function handleOptionalObjectResult(result: ParsePayload, final: ParsePayload, k
       // if input was undefined, ignore the error
       if (key in input) {
         (final.value as any)[key] = undefined;
+      } else {
+        (final.value as any)[key] = result.value;
       }
     } else {
       final.issues.push(...util.prefixIssues(key, result.issues));
@@ -1611,13 +1638,32 @@ function handleOptionalObjectResult(result: ParsePayload, final: ParsePayload, k
   }
 }
 
+export type $ZodObjectConfig = { out: Record<string, unknown>; in: Record<string, unknown> };
+
+export type $loose = {
+  out: Record<string, unknown>;
+  in: Record<string, unknown>;
+};
+export type $strict = {
+  out: {};
+  in: {};
+};
+export type $strip = {
+  out: {};
+  in: {};
+};
+export type $catchall<T extends $ZodType> = {
+  out: { [k: string]: core.output<T> };
+  in: { [k: string]: core.input<T> };
+};
 export interface $ZodObject<
   // @ts-ignore Cast variance
   out Shape extends Readonly<$ZodShape> = Readonly<$ZodShape>,
-  out OutExtra extends Record<string, unknown> = Record<string, unknown>,
-  out InExtra extends Record<string, unknown> = Record<string, unknown>,
+  out Params extends $ZodObjectConfig = $ZodObjectConfig,
+  // out OutExtra extends Record<string, unknown> = Record<string, unknown>,
+  // out InExtra extends Record<string, unknown> = Record<string, unknown>,
 > extends $ZodType {
-  _zod: $ZodObjectInternals<Shape, OutExtra, InExtra>;
+  _zod: $ZodObjectInternals<Shape, Params>;
 }
 
 export const $ZodObject: core.$constructor<$ZodObject> = /*@__PURE__*/ core.$constructor("$ZodObject", (inst, def) => {
@@ -1717,8 +1763,9 @@ export const $ZodObject: core.$constructor<$ZodObject> = /*@__PURE__*/ core.$con
         } else if (${id}.value === undefined) {
           if (${k} in input) payload.value[${k}] = undefined;
         } else {
-          payload.value[${k}] = ${id}.value;
-        }  
+          if (${k} in input) payload.value[${k}] = ${id}.value;
+        }
+          
         `);
     }
 
@@ -1753,7 +1800,7 @@ export const $ZodObject: core.$constructor<$ZodObject> = /*@__PURE__*/ core.$con
 
     const proms: Promise<any>[] = [];
 
-    if (jit && fastEnabled && ctx?.async === false && ctx.noPrecompilation !== true) {
+    if (jit && fastEnabled && ctx?.async === false && ctx.jitless !== true) {
       // always synchronous
       if (!fastpass) fastpass = generateFastpass(def.shape);
       payload = fastpass(payload, ctx);
@@ -1948,21 +1995,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;
@@ -1976,8 +2032,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(),
@@ -1994,13 +2051,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) => {
@@ -2016,15 +2070,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;
@@ -2032,13 +2095,7 @@ export const $ZodDiscriminatedUnion: core.$constructor<$ZodDiscriminatedUnion> =
       if (def.unionFallback) {
         return _super(payload, ctx);
       }
-      payload.issues.push({
-        code: "invalid_union",
-        errors: [],
-        note: "No matching discriminator",
-        input,
-        inst,
-      });
+
       return payload;
     };
   });
@@ -2309,9 +2366,8 @@ export const $ZodTuple: core.$constructor<$ZodTuple> = /*@__PURE__*/ core.$const
 function handleTupleResult(result: ParsePayload, final: ParsePayload<any[]>, index: number) {
   if (result.issues.length) {
     final.issues.push(...util.prefixIssues(index, result.issues));
-  } else {
-    final.value[index] = result.value;
   }
+  final.value[index] = result.value;
 }
 
 //////////////////////////////////////////
@@ -2443,6 +2499,7 @@ export const $ZodRecord: core.$constructor<$ZodRecord> = /*@__PURE__*/ core.$con
             path: [key],
             inst,
           });
+          payload.value[keyResult.value as PropertyKey] = keyResult.value;
           continue;
         }
 
@@ -2453,17 +2510,15 @@ export const $ZodRecord: core.$constructor<$ZodRecord> = /*@__PURE__*/ core.$con
             result.then((result) => {
               if (result.issues.length) {
                 payload.issues.push(...util.prefixIssues(key, result.issues));
-              } else {
-                payload.value[keyResult.value as PropertyKey] = result.value;
               }
+              payload.value[keyResult.value as PropertyKey] = result.value;
             })
           );
         } else {
           if (result.issues.length) {
             payload.issues.push(...util.prefixIssues(key, result.issues));
-          } else {
-            payload.value[keyResult.value as PropertyKey] = result.value;
           }
+          payload.value[keyResult.value as PropertyKey] = result.value;
         }
       }
     }
@@ -2571,9 +2626,8 @@ function handleMapResult(
         issues: valueResult.issues.map((iss) => util.finalizeIssue(iss, ctx, core.config())),
       });
     }
-  } else {
-    final.value.set(keyResult.value, valueResult.value);
   }
+  final.value.set(keyResult.value, valueResult.value);
 }
 
 ///////////////////////////////////////
@@ -2630,9 +2684,8 @@ export const $ZodSet: core.$constructor<$ZodSet> = /*@__PURE__*/ core.$construct
 function handleSetResult(result: ParsePayload, final: ParsePayload<Set<any>>) {
   if (result.issues.length) {
     final.issues.push(...result.issues);
-  } else {
-    final.value.add(result.value);
   }
+  final.value.add(result.value);
 }
 
 ////////////////////////////////////////
@@ -2643,7 +2696,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";
@@ -2802,6 +2855,8 @@ export const $ZodLiteral: core.$constructor<$ZodLiteral> = /*@__PURE__*/ core.$c
 //////////////////////////////////////////
 //////////////////////////////////////////
 
+// provide a fallback in case the File interface isn't provided in the environment
+interface File {}
 export interface $ZodFileDef extends $ZodTypeDef {
   type: "file";
 }
@@ -2841,7 +2896,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;
@@ -2895,7 +2949,7 @@ export interface $ZodOptionalInternals<T extends $ZodType = $ZodType>
   optionality: "optional";
   isst: never;
   values: T["_zod"]["values"];
-  pattern: RegExp;
+  pattern: T["_zod"]["pattern"];
 }
 
 export interface $ZodOptional<T extends $ZodType = $ZodType> extends $ZodType {
@@ -2907,10 +2961,14 @@ export const $ZodOptional: core.$constructor<$ZodOptional> = /*@__PURE__*/ core.
   (inst, def) => {
     $ZodType.init(inst, def);
     inst._zod.optionality = "optional";
-    if (def.innerType._zod.values) inst._zod.values = new Set([...def.innerType._zod.values, undefined]);
 
-    const pattern = (def.innerType as any)._zod.pattern;
-    if (pattern) inst._zod.pattern = new RegExp(`^(${util.cleanRegex(pattern.source)})?$`);
+    util.defineLazy(inst._zod, "values", () =>
+      def.innerType._zod.values ? new Set([...def.innerType._zod.values, undefined]) : undefined
+    );
+    util.defineLazy(inst._zod, "pattern", () => {
+      const pattern = def.innerType._zod.pattern;
+      return pattern ? new RegExp(`^(${util.cleanRegex(pattern.source)})?$`) : undefined;
+    });
 
     inst._zod.parse = (payload, ctx) => {
       if (payload.value === undefined) {
@@ -2939,7 +2997,7 @@ export interface $ZodNullableInternals<T extends $ZodType = $ZodType>
   optionality: T["_zod"]["optionality"];
   isst: never;
   values: T["_zod"]["values"];
-  pattern: RegExp;
+  pattern: T["_zod"]["pattern"];
 }
 
 export interface $ZodNullable<T extends $ZodType = $ZodType> extends $ZodType {
@@ -2950,12 +3008,16 @@ export const $ZodNullable: core.$constructor<$ZodNullable> = /*@__PURE__*/ core.
   "$ZodNullable",
   (inst, def) => {
     $ZodType.init(inst, def);
-    inst._zod.optionality = def.innerType._zod.optionality;
+    util.defineLazy(inst._zod, "optionality", () => def.innerType._zod.optionality);
 
-    const pattern = (def.innerType as any)._zod.pattern;
-    if (pattern) inst._zod.pattern = new RegExp(`^(${util.cleanRegex(pattern.source)}|null)$`);
+    util.defineLazy(inst._zod, "pattern", () => {
+      const pattern = def.innerType._zod.pattern;
+      return pattern ? new RegExp(`^(${util.cleanRegex(pattern.source)}|null)$`) : undefined;
+    });
 
-    if (def.innerType._zod.values) inst._zod.values = new Set([...def.innerType._zod.values, null]);
+    util.defineLazy(inst._zod, "values", () => {
+      return def.innerType._zod.values ? new Set([...def.innerType._zod.values, null]) : undefined;
+    });
 
     inst._zod.parse = (payload, ctx) => {
       if (payload.value === null) return payload;
@@ -2975,15 +3037,12 @@ export const $ZodNullable: core.$constructor<$ZodNullable> = /*@__PURE__*/ core.
 export interface $ZodDefaultDef<T extends $ZodType = $ZodType> extends $ZodTypeDef {
   type: "default";
   innerType: T;
-  defaultValue: () => util.NoUndefined<core.output<T>>;
+  /** The default value. May be a getter. */
+  defaultValue: util.NoUndefined<core.output<T>>;
 }
 
 export interface $ZodDefaultInternals<T extends $ZodType = $ZodType>
-  extends $ZodTypeInternals<
-    // this is pragmatic but not strictly correct
-    util.NoUndefined<core.output<T>>,
-    core.input<T> | undefined
-  > {
+  extends $ZodTypeInternals<util.NoUndefined<core.output<T>>, core.input<T> | undefined> {
   def: $ZodDefaultDef<T>;
   // qin: "true";
   optionality: "defaulted";
@@ -3002,11 +3061,11 @@ export const $ZodDefault: core.$constructor<$ZodDefault> = /*@__PURE__*/ core.$c
 
     // inst._zod.qin = "true";
     inst._zod.optionality = "defaulted";
-    inst._zod.values = def.innerType._zod.values;
+    util.defineLazy(inst._zod, "values", () => def.innerType._zod.values);
 
     inst._zod.parse = (payload, ctx) => {
       if (payload.value === undefined) {
-        payload.value = def.defaultValue();
+        payload.value = def.defaultValue;
         /**
          * $ZodDefault always returns the default value immediately.
          * It doesn't pass the default value into the validator ("prefault"). There's no reason to pass the default value through validation. The validity of the default is enforced by TypeScript statically. Otherwise, it's the responsibility of the user to ensure the default is valid. In the case of pipes with divergent in/out types, you can specify the default on the `in` schema of your ZodPipe to set a "prefault" for the pipe.   */
@@ -3023,10 +3082,55 @@ export const $ZodDefault: core.$constructor<$ZodDefault> = /*@__PURE__*/ core.$c
 
 function handleDefaultResult(payload: ParsePayload, def: $ZodDefaultDef) {
   if (payload.value === undefined) {
-    payload.value = def.defaultValue();
+    payload.value = def.defaultValue;
   }
   return payload;
 }
+
+////////////////////////////////////////////
+////////////////////////////////////////////
+//////////                        //////////
+//////////      $ZodPrefault      //////////
+//////////                        //////////
+////////////////////////////////////////////
+////////////////////////////////////////////
+
+export interface $ZodPrefaultDef<T extends $ZodType = $ZodType> extends $ZodTypeDef {
+  type: "prefault";
+  innerType: T;
+  /** The default value. May be a getter. */
+  defaultValue: core.input<T>;
+}
+
+export interface $ZodPrefaultInternals<T extends $ZodType = $ZodType>
+  extends $ZodTypeInternals<util.NoUndefined<core.output<T>>, core.input<T> | undefined> {
+  def: $ZodPrefaultDef<T>;
+  optionality: "defaulted";
+  isst: never;
+  values: T["_zod"]["values"];
+}
+
+export interface $ZodPrefault<T extends $ZodType = $ZodType> extends $ZodType {
+  _zod: $ZodPrefaultInternals<T>;
+}
+
+export const $ZodPrefault: core.$constructor<$ZodPrefault> = /*@__PURE__*/ core.$constructor(
+  "$ZodPrefault",
+  (inst, def) => {
+    $ZodType.init(inst, def);
+
+    inst._zod.optionality = "defaulted";
+    util.defineLazy(inst._zod, "values", () => def.innerType._zod.values);
+
+    inst._zod.parse = (payload, ctx) => {
+      if (payload.value === undefined) {
+        payload.value = def.defaultValue;
+      }
+      return def.innerType._zod.run(payload, ctx);
+    };
+  }
+);
+
 ///////////////////////////////////////////////
 ///////////////////////////////////////////////
 //////////                           //////////
@@ -3054,8 +3158,12 @@ export const $ZodNonOptional: core.$constructor<$ZodNonOptional> = /*@__PURE__*/
   "$ZodNonOptional",
   (inst, def) => {
     $ZodType.init(inst, def);
-    if (def.innerType._zod.values)
-      inst._zod.values = new Set([...def.innerType._zod.values].filter((x) => x !== undefined));
+
+    util.defineLazy(inst._zod, "values", () => {
+      const v = def.innerType._zod.values;
+      return v ? new Set([...v].filter((x) => x !== undefined)) : undefined;
+    });
+
     inst._zod.parse = (payload, ctx) => {
       const result = def.innerType._zod.run(payload, ctx);
       if (result instanceof Promise) {
@@ -3194,13 +3302,14 @@ export interface $ZodCatch<T extends $ZodType = $ZodType> extends $ZodType {
 
 export const $ZodCatch: core.$constructor<$ZodCatch> = /*@__PURE__*/ core.$constructor("$ZodCatch", (inst, def) => {
   $ZodType.init(inst, def);
-  inst._zod.optionality = def.innerType._zod.optionality;
-  inst._zod.values = def.innerType._zod.values;
+  util.defineLazy(inst._zod, "optionality", () => def.innerType._zod.optionality);
+  util.defineLazy(inst._zod, "values", () => def.innerType._zod.values);
 
   inst._zod.parse = (payload, ctx) => {
     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,
@@ -3210,13 +3319,13 @@ export const $ZodCatch: core.$constructor<$ZodCatch> = /*@__PURE__*/ core.$const
             input: payload.value,
           });
           payload.issues = [];
-        } else {
-          payload.value = result.value;
         }
+
         return payload;
       });
     }
 
+    payload.value = result.value;
     if (result.issues.length) {
       payload.value = def.catchValue({
         ...payload,
@@ -3226,9 +3335,8 @@ export const $ZodCatch: core.$constructor<$ZodCatch> = /*@__PURE__*/ core.$const
         input: payload.value,
       });
       payload.issues = [];
-    } else {
-      payload.value = result.value;
     }
+
     return payload;
   };
 });
@@ -3349,7 +3457,7 @@ export const $ZodReadonly: core.$constructor<$ZodReadonly> = /*@__PURE__*/ core.
   (inst, def) => {
     $ZodType.init(inst, def);
     util.defineLazy(inst._zod, "disc", () => def.innerType._zod.disc);
-    inst._zod.optionality = def.innerType._zod.optionality;
+    util.defineLazy(inst._zod, "optionality", () => def.innerType._zod.optionality);
 
     inst._zod.parse = (payload, ctx) => {
       const result = def.innerType._zod.run(payload, ctx);
@@ -3597,7 +3705,7 @@ function handleRefineResult(result: unknown, payload: ParsePayload, input: unkno
       code: "custom",
       input,
       inst, // incorporates params.error into issue reporting
-      path: inst._zod.def.path, // incorporates params.error into issue reporting
+      path: [...(inst._zod.def.path ?? [])], // incorporates params.error into issue reporting
       continue: !inst._zod.def.abort,
       // params: inst._zod.def.params,
     };
@@ -3634,6 +3742,7 @@ export type $ZodTypes =
   | $ZodLazy
   | $ZodOptional
   | $ZodDefault
+  | $ZodPrefault
   | $ZodTemplateLiteral
   | $ZodCustom
   | $ZodTransform
diff --git a/packages/zod/src/v4/core/to-json-schema.ts b/packages/zod/src/v4/core/to-json-schema.ts
index abd4d697..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,15 +436,22 @@ export class JSONSchemaGenerator {
           break;
         }
         case "default": {
-          const inner = this.process(def.innerType, params);
-          Object.assign(_json, inner);
-          _json.default = def.defaultValue();
+          this.process(def.innerType, params);
+          result.ref = def.innerType;
+          _json.default = def.defaultValue;
+          break;
+        }
+        case "prefault": {
+          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);
@@ -489,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;
@@ -514,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": {
@@ -547,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;
   }
 
@@ -572,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.");
@@ -614,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
@@ -680,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];
@@ -705,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));
@@ -715,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 264d9d37..affb0cd1 100644
--- a/packages/zod/src/v4/core/util.ts
+++ b/packages/zod/src/v4/core/util.ts
@@ -321,7 +321,8 @@ export function isObject(data: any): data is Record<PropertyKey, unknown> {
 
 export const allowsEval: { value: boolean } = cached(() => {
   try {
-    new Function("");
+    const F = Function;
+    new F("");
     return true;
   } catch (_) {
     return false;
@@ -746,8 +747,8 @@ export function finalizeIssue(
   config: $ZodConfig
 ): errors.$ZodIssue {
   const full = { ...iss, path: iss.path ?? [] } as errors.$ZodIssue;
+
   // for backwards compatibility
-  // const _ctx: errors.$ZodErrorMapCtx = { data: iss.input, defaultError: undefined as any };
   if (!iss.message) {
     const message =
       unwrapMessage(iss.inst?._zod.def?.error?.(iss as never)) ??
@@ -764,6 +765,7 @@ export function finalizeIssue(
   if (!ctx?.reportInput) {
     delete (full as any).input;
   }
+
   return full;
 }
 
@@ -805,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/coerce.ts b/packages/zod/src/v4/mini/coerce.ts
index 7d322da6..435ccf20 100644
--- a/packages/zod/src/v4/mini/coerce.ts
+++ b/packages/zod/src/v4/mini/coerce.ts
@@ -1,22 +1,22 @@
 import * as core from "zod/v4/core";
 import * as schemas from "./schemas.js";
 
-export function string(params?: string | core.$ZodStringParams): schemas.ZodMiniString<unknown> {
-  return core._coercedString(schemas.ZodMiniString, params);
+export function string<T = unknown>(params?: string | core.$ZodStringParams): schemas.ZodMiniString<T> {
+  return core._coercedString(schemas.ZodMiniString, params) as schemas.ZodMiniString<T>;
 }
 
-export function number(params?: string | core.$ZodNumberParams): schemas.ZodMiniNumber<unknown> {
-  return core._coercedNumber(schemas.ZodMiniNumber, params);
+export function number<T = unknown>(params?: string | core.$ZodNumberParams): schemas.ZodMiniNumber<T> {
+  return core._coercedNumber(schemas.ZodMiniNumber, params) as schemas.ZodMiniNumber<T>;
 }
 
-export function boolean(params?: string | core.$ZodBooleanParams): schemas.ZodMiniBoolean<unknown> {
-  return core._coercedBoolean(schemas.ZodMiniBoolean, params);
+export function boolean<T = unknown>(params?: string | core.$ZodBooleanParams): schemas.ZodMiniBoolean<T> {
+  return core._coercedBoolean(schemas.ZodMiniBoolean, params) as schemas.ZodMiniBoolean<T>;
 }
 
-export function bigint(params?: string | core.$ZodBigIntParams): schemas.ZodMiniBigInt<unknown> {
-  return core._coercedBigint(schemas.ZodMiniBigInt, params);
+export function bigint<T = unknown>(params?: string | core.$ZodBigIntParams): schemas.ZodMiniBigInt<T> {
+  return core._coercedBigint(schemas.ZodMiniBigInt, params) as schemas.ZodMiniBigInt<T>;
 }
 
-export function date(params?: string | core.$ZodDateParams): schemas.ZodMiniDate<unknown> {
-  return core._coercedDate(schemas.ZodMiniDate, params);
+export function date<T = unknown>(params?: string | core.$ZodDateParams): schemas.ZodMiniDate<T> {
+  return core._coercedDate(schemas.ZodMiniDate, params) as schemas.ZodMiniDate<T>;
 }
diff --git a/packages/zod/src/v4/mini/external.ts b/packages/zod/src/v4/mini/external.ts
index abca7df7..5276a9c0 100644
--- a/packages/zod/src/v4/mini/external.ts
+++ b/packages/zod/src/v4/mini/external.ts
@@ -14,10 +14,10 @@ export {
   function,
   clone,
   regexes,
-  // flattenError,
-  // formatError,
   treeifyError,
   prettifyError,
+  formatError,
+  flattenError,
   toJSONSchema,
   locales,
 } from "zod/v4/core";
diff --git a/packages/zod/src/v4/mini/schemas.ts b/packages/zod/src/v4/mini/schemas.ts
index 66be2862..ef86000d 100644
--- a/packages/zod/src/v4/mini/schemas.ts
+++ b/packages/zod/src/v4/mini/schemas.ts
@@ -694,10 +694,9 @@ export function keyof<T extends ZodMiniObject>(schema: T): ZodMiniLiteral<keyof
 export interface ZodMiniObject<
   // @ts-ignore Cast variance
   out Shape extends core.$ZodShape = core.$ZodShape,
-  OutExtra extends Record<string, unknown> = Record<string, unknown>,
-  InExtra extends Record<string, unknown> = Record<string, unknown>,
+  out Config extends core.$ZodObjectConfig = core.$ZodObjectConfig,
 > extends ZodMiniType {
-  _zod: core.$ZodObjectInternals<Shape, OutExtra, InExtra>;
+  _zod: core.$ZodObjectInternals<Shape, Config>;
   shape: Shape;
 }
 export const ZodMiniObject: core.$constructor<ZodMiniObject> = /*@__PURE__*/ core.$constructor(
@@ -710,7 +709,7 @@ export const ZodMiniObject: core.$constructor<ZodMiniObject> = /*@__PURE__*/ cor
 export function object<T extends core.$ZodLooseShape = Record<never, SomeType>>(
   shape?: T,
   params?: string | core.$ZodObjectParams
-): ZodMiniObject<T, {}, {}> {
+): ZodMiniObject<T, core.$strip> {
   const def: core.$ZodObjectDef = {
     type: "object",
     get shape() {
@@ -727,7 +726,7 @@ export function object<T extends core.$ZodLooseShape = Record<never, SomeType>>(
 export function strictObject<T extends core.$ZodLooseShape>(
   shape: T,
   params?: string | core.$ZodObjectParams
-): ZodMiniObject<T, {}, {}> {
+): ZodMiniObject<T, core.$strict> {
   return new ZodMiniObject({
     type: "object",
     // shape: shape as core.$ZodLooseShape,
@@ -748,7 +747,7 @@ export function strictObject<T extends core.$ZodLooseShape>(
 export function looseObject<T extends core.$ZodLooseShape>(
   shape: T,
   params?: string | core.$ZodObjectParams
-): ZodMiniObject<T, { [k: string]: unknown }, { [k: string]: unknown }> {
+): ZodMiniObject<T, core.$loose> {
   return new ZodMiniObject({
     type: "object",
     // shape: shape as core.$ZodLooseShape,
@@ -768,7 +767,7 @@ export function looseObject<T extends core.$ZodLooseShape>(
 export function extend<T extends ZodMiniObject, U extends core.$ZodLooseShape>(
   schema: T,
   shape: U
-): ZodMiniObject<util.Extend<T["shape"], U>, T["_zod"]["outextra"], T["_zod"]["inextra"]> {
+): ZodMiniObject<util.Extend<T["shape"], U>, T["_zod"]["config"]> {
   return util.extend(schema, shape);
 }
 
@@ -776,7 +775,7 @@ export function extend<T extends ZodMiniObject, U extends core.$ZodLooseShape>(
 export function merge<T extends ZodMiniObject, U extends ZodMiniObject>(
   a: T,
   b: U
-): ZodMiniObject<util.Extend<T["shape"], U["shape"]>, T["_zod"]["outextra"], T["_zod"]["inextra"]>;
+): ZodMiniObject<util.Extend<T["shape"], U["shape"]>, T["_zod"]["config"]>;
 export function merge(schema: ZodMiniObject, shape: any): ZodMiniObject {
   return util.extend(schema, shape);
 }
@@ -784,11 +783,7 @@ export function merge(schema: ZodMiniObject, shape: any): ZodMiniObject {
 export function pick<T extends ZodMiniObject, M extends util.Mask<keyof T["shape"]>>(
   schema: T,
   mask: M
-): ZodMiniObject<
-  util.Flatten<Pick<T["shape"], keyof T["shape"] & keyof M>>,
-  T["_zod"]["outextra"],
-  T["_zod"]["inextra"]
-> {
+): ZodMiniObject<util.Flatten<Pick<T["shape"], keyof T["shape"] & keyof M>>, T["_zod"]["config"]> {
   return util.pick(schema, mask as any);
 }
 
@@ -797,7 +792,7 @@ export function pick<T extends ZodMiniObject, M extends util.Mask<keyof T["shape
 export function omit<T extends ZodMiniObject, const M extends util.Mask<keyof T["shape"]>>(
   schema: T,
   mask: M
-): ZodMiniObject<util.Flatten<Omit<T["shape"], keyof M>>, T["_zod"]["outextra"], T["_zod"]["inextra"]> {
+): ZodMiniObject<util.Flatten<Omit<T["shape"], keyof M>>, T["_zod"]["config"]> {
   return util.omit(schema, mask);
 }
 
@@ -807,8 +802,7 @@ export function partial<T extends ZodMiniObject>(
   {
     [k in keyof T["shape"]]: ZodMiniOptional<T["shape"][k]>;
   },
-  T["_zod"]["outextra"],
-  T["_zod"]["inextra"]
+  T["_zod"]["config"]
 >;
 export function partial<T extends ZodMiniObject, M extends util.Mask<keyof T["shape"]>>(
   schema: T,
@@ -817,8 +811,7 @@ export function partial<T extends ZodMiniObject, M extends util.Mask<keyof T["sh
   {
     [k in keyof T["shape"]]: k extends keyof M ? ZodMiniOptional<T["shape"][k]> : T["shape"][k];
   },
-  T["_zod"]["outextra"],
-  T["_zod"]["inextra"]
+  T["_zod"]["config"]
 >;
 export function partial(schema: ZodMiniObject, mask?: object) {
   return util.partial(ZodMiniOptional, schema, mask);
@@ -841,8 +834,7 @@ export function required<T extends ZodMiniObject>(
   {
     [k in keyof T["shape"]]: ZodMiniNonOptional<T["shape"][k]>;
   },
-  T["_zod"]["outextra"],
-  T["_zod"]["inextra"]
+  T["_zod"]["config"]
 >;
 export function required<T extends ZodMiniObject, M extends util.Mask<keyof T["shape"]>>(
   schema: T,
@@ -854,8 +846,7 @@ export function required<T extends ZodMiniObject, M extends util.Mask<keyof T["s
       [k in keyof M & keyof T["shape"]]: ZodMiniNonOptional<T["shape"][k]>;
     }
   >,
-  T["_zod"]["outextra"],
-  T["_zod"]["inextra"]
+  T["_zod"]["config"]
 >;
 export function required(schema: ZodMiniObject, mask?: object) {
   return util.required(ZodMiniNonOptional, schema, mask);
@@ -1154,13 +1145,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;
 }
 
@@ -1225,9 +1214,35 @@ export function _default<T extends SomeType>(
 ): ZodMiniDefault<T> {
   return new ZodMiniDefault({
     type: "default",
-    defaultValue: (typeof defaultValue === "function" ? defaultValue : () => defaultValue) as () => core.output<T>,
     innerType,
-  }) as any as ZodMiniDefault<T>;
+    get defaultValue() {
+      return typeof defaultValue === "function" ? (defaultValue as Function)() : defaultValue;
+    },
+  }) as ZodMiniDefault<T>;
+}
+
+// ZodMiniPrefault
+export interface ZodMiniPrefault<T extends SomeType = SomeType> extends ZodMiniType {
+  _zod: core.$ZodPrefaultInternals<T>;
+}
+export const ZodMiniPrefault: core.$constructor<ZodMiniPrefault> = /*@__PURE__*/ core.$constructor(
+  "ZodMiniPrefault",
+  (inst, def) => {
+    core.$ZodPrefault.init(inst, def);
+    ZodMiniType.init(inst, def);
+  }
+);
+export function prefault<T extends SomeType>(
+  innerType: T,
+  defaultValue: util.NoUndefined<core.input<T>> | (() => util.NoUndefined<core.input<T>>)
+): ZodMiniPrefault<T> {
+  return new ZodMiniPrefault({
+    type: "prefault",
+    innerType,
+    get defaultValue() {
+      return typeof defaultValue === "function" ? (defaultValue as Function)() : defaultValue;
+    },
+  }) as ZodMiniPrefault<T>;
 }
 
 // ZodMiniNonOptional
diff --git a/play.ts b/play.ts
index 82831bb2..1263049d 100644
--- a/play.ts
+++ b/play.ts
@@ -1,5 +1,12 @@
-import * as z from "zod/v4";
+import { z } from "zod/v4";
 
-// z.string().check(z.startsWith("asdf", "bad")).parse("qwer");
+z;
 
-console.log(z.string().includes("Error")._zod.def);
+const stringWithDefault = z
+  .pipe(
+    z.transform((v) => (v === "none" ? undefined : v)),
+    z.string()
+  )
+  .catch("default");
+
+stringWithDefault.parse(undefined);


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/coerce.test.ts b/packages/zod/src/v4/classic/tests/coerce.test.ts
index 71345c5a..136a3827 100644
--- a/packages/zod/src/v4/classic/tests/coerce.test.ts
+++ b/packages/zod/src/v4/classic/tests/coerce.test.ts
@@ -1,4 +1,4 @@
-import { expect, test } from "vitest";
+import { expect, expectTypeOf, test } from "vitest";
 
 import * as z from "zod/v4";
 
@@ -150,3 +150,11 @@ test("date coercion", () => {
 //   expect(schema.parse("300vmax")).toEqual("300vmax");
 //   expect(schema.parse(["300px"])).toEqual("300px");
 // });
+
+test("override input type", () => {
+  const a = z.coerce.string<any>();
+  type input = z.input<typeof a>;
+  expectTypeOf<input>().toEqualTypeOf<any>();
+  type output = z.infer<typeof a>;
+  expectTypeOf<output>().toEqualTypeOf<string>();
+});
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..98151ec0 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"
@@ -399,6 +441,14 @@ test("z.toDotPath", () => {
     `"user.$special["Symbol(#symbol)"]"`
   );
 
+  // Test with dots and quotes
+  expect(z.core.toDotPath(["search", `query("foo.bar"="abc")`])).toMatchInlineSnapshot(
+    `"search["query(\\"foo.bar\\"=\\"abc\\")"]"`
+  );
+
+  // Test with newlines
+  expect(z.core.toDotPath(["search", `foo\nbar`])).toMatchInlineSnapshot(`"search["foo\\nbar"]"`);
+
   // Test with empty strings
   expect(z.core.toDotPath(["", "empty"])).toMatchInlineSnapshot(`".empty"`);
 
@@ -411,7 +461,7 @@ test("z.toDotPath", () => {
   );
 
   // Test with square brackets in keys
-  expect(z.core.toDotPath(["data[0]", "value"])).toMatchInlineSnapshot(`"data[0].value"`);
+  expect(z.core.toDotPath(["data[0]", "value"])).toMatchInlineSnapshot(`"["data[0]"].value"`);
 
   // Test with empty path
   expect(z.core.toDotPath([])).toMatchInlineSnapshot(`""`);
@@ -419,10 +469,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/firstparty.test.ts b/packages/zod/src/v4/classic/tests/firstparty.test.ts
index 31912948..ac689930 100644
--- a/packages/zod/src/v4/classic/tests/firstparty.test.ts
+++ b/packages/zod/src/v4/classic/tests/firstparty.test.ts
@@ -60,6 +60,8 @@ test("first party switch", () => {
       break;
     case "default":
       break;
+    case "prefault":
+      break;
     case "template_literal":
       break;
     case "custom":
@@ -146,6 +148,8 @@ test("$ZodSchemaTypes", () => {
       break;
     case "default":
       break;
+    case "prefault":
+      break;
     case "template_literal":
       break;
     case "custom":
@@ -166,6 +170,7 @@ test("$ZodSchemaTypes", () => {
       break;
     case "lazy":
       break;
+
     default:
       expectTypeOf(type).toEqualTypeOf<never>();
   }
diff --git a/packages/zod/src/v4/classic/tests/intersection.test.ts b/packages/zod/src/v4/classic/tests/intersection.test.ts
index 76d045f1..d1538c03 100644
--- a/packages/zod/src/v4/classic/tests/intersection.test.ts
+++ b/packages/zod/src/v4/classic/tests/intersection.test.ts
@@ -21,7 +21,7 @@ test("object intersection: loose", () => {
 
   const C = z.intersection(A, B); // BaseC.merge(HasID);
   type C = z.infer<typeof C>;
-  expectTypeOf<C>().toEqualTypeOf<{ a: string } & { b: string } & Record<string, unknown>>();
+  expectTypeOf<C>().toEqualTypeOf<{ a: string; [x: string]: unknown } & { b: string }>();
   const data = { a: "foo", b: "foo", c: "extra" };
   expect(C.parse(data)).toEqual(data);
   expect(() => C.parse({ a: "foo" })).toThrow();
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 e2faabf5..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,12 +1373,60 @@ 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(),
     b: z.string().optional(),
     c: z.string().default("hello"),
     d: z.string().nullable(),
+    e: z.string().prefault("hello"),
   });
   expect(toJSONSchema(schema, { io: "input" })).toMatchInlineSnapshot(`
     {
@@ -1382,6 +1451,10 @@ test("input type", () => {
             },
           ],
         },
+        "e": {
+          "default": "hello",
+          "type": "string",
+        },
       },
       "required": [
         "a",
@@ -1413,13 +1486,61 @@ test("input type", () => {
             },
           ],
         },
+        "e": {
+          "type": "string",
+        },
       },
       "required": [
         "a",
         "c",
         "d",
+        "e",
       ],
       "type": "object",
     }
   `);
 });
+
+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/lazy.test.ts b/packages/zod/src/v4/classic/tests/lazy.test.ts
index 0910859d..f4db9d8c 100644
--- a/packages/zod/src/v4/classic/tests/lazy.test.ts
+++ b/packages/zod/src/v4/classic/tests/lazy.test.ts
@@ -28,7 +28,7 @@ test("opt passthrough", () => {
       a: "hello",
       b: undefined,
     },
-    { noPrecompilation: true }
+    { jitless: true }
   );
   expect(result).toEqual({
     a: "hello",
@@ -200,3 +200,23 @@ test("complicated self-recursion", () => {
 
   type _Category = z.output<typeof Category>;
 });
+
+test("lazy initialization", () => {
+  const a: any = z.lazy(() => a).optional();
+  const b: any = z.lazy(() => b).nullable();
+  const c: any = z.lazy(() => c).default({} as any);
+  const d: any = z.lazy(() => d).prefault({} as any);
+  const e: any = z.lazy(() => e).nonoptional();
+  const f: any = z.lazy(() => f).catch({} as any);
+  const g: any = z.lazy(() => z.object({ g })).readonly();
+
+  const baseCategorySchema = z.object({
+    name: z.string(),
+  });
+  type Category = z.infer<typeof baseCategorySchema> & {
+    subcategories: Category[];
+  };
+  const categorySchema: z.ZodType<Category> = baseCategorySchema.extend({
+    subcategories: z.lazy(() => categorySchema.array()),
+  });
+});
diff --git a/packages/zod/src/v4/classic/tests/nested-refine.test.ts b/packages/zod/src/v4/classic/tests/nested-refine.test.ts
new file mode 100644
index 00000000..c6bd90f6
--- /dev/null
+++ b/packages/zod/src/v4/classic/tests/nested-refine.test.ts
@@ -0,0 +1,169 @@
+import { expect, test } from "vitest";
+import * as z from "zod/v4";
+
+test("nested refinements", () => {
+  const zodSchema = z
+    .object({
+      password: z.string().min(1),
+      nested: z
+        .object({
+          confirm: z
+            .string()
+            .min(1)
+            .refine((value) => value.length > 2, {
+              message: "Confirm length should be > 2",
+            }),
+        })
+        .refine(
+          (data) => {
+            return data.confirm === "bar";
+          },
+          {
+            path: ["confirm"],
+            error: 'Value must be "bar"',
+          }
+        ),
+    })
+    .refine(
+      (data) => {
+        return data.nested.confirm === data.password;
+      },
+      {
+        path: ["nested", "confirm"],
+        error: "Password and confirm must match",
+      }
+    );
+
+  const DATA = {
+    password: "bar",
+    nested: { confirm: "" },
+  };
+  expect(zodSchema.safeParse(DATA)).toMatchInlineSnapshot(`
+    {
+      "error": ZodError {
+        "issues": [
+          {
+            "code": "too_small",
+            "message": "Too small: expected string to have >1 characters",
+            "minimum": 1,
+            "origin": "string",
+            "path": [
+              "nested",
+              "confirm",
+            ],
+          },
+          {
+            "code": "custom",
+            "message": "Confirm length should be > 2",
+            "path": [
+              "nested",
+              "confirm",
+            ],
+          },
+          {
+            "code": "custom",
+            "message": "Value must be "bar"",
+            "path": [
+              "nested",
+              "confirm",
+            ],
+          },
+          {
+            "code": "custom",
+            "message": "Password and confirm must match",
+            "path": [
+              "nested",
+              "confirm",
+            ],
+          },
+        ],
+      },
+      "success": false,
+    }
+  `);
+
+  expect(zodSchema.safeParse(DATA, { jitless: true })).toMatchInlineSnapshot(`
+    {
+      "error": ZodError {
+        "issues": [
+          {
+            "code": "too_small",
+            "message": "Too small: expected string to have >1 characters",
+            "minimum": 1,
+            "origin": "string",
+            "path": [
+              "nested",
+              "confirm",
+            ],
+          },
+          {
+            "code": "custom",
+            "message": "Confirm length should be > 2",
+            "path": [
+              "nested",
+              "confirm",
+            ],
+          },
+          {
+            "code": "custom",
+            "message": "Value must be "bar"",
+            "path": [
+              "nested",
+              "confirm",
+            ],
+          },
+          {
+            "code": "custom",
+            "message": "Password and confirm must match",
+            "path": [
+              "nested",
+              "confirm",
+            ],
+          },
+        ],
+      },
+      "success": false,
+    }
+  `);
+
+  expect(zodSchema["~standard"].validate(DATA)).toMatchInlineSnapshot(`
+    {
+      "issues": [
+        {
+          "code": "too_small",
+          "message": "Too small: expected string to have >1 characters",
+          "minimum": 1,
+          "origin": "string",
+          "path": [
+            "nested",
+            "confirm",
+          ],
+        },
+        {
+          "code": "custom",
+          "message": "Confirm length should be > 2",
+          "path": [
+            "nested",
+            "confirm",
+          ],
+        },
+        {
+          "code": "custom",
+          "message": "Value must be "bar"",
+          "path": [
+            "nested",
+            "confirm",
+          ],
+        },
+        {
+          "code": "custom",
+          "message": "Password and confirm must match",
+          "path": [
+            "nested",
+            "confirm",
+          ],
+        },
+      ],
+    }
+  `);
+});
diff --git a/packages/zod/src/v4/classic/tests/object.test.ts b/packages/zod/src/v4/classic/tests/object.test.ts
index 3c58c6b6..0429eade 100644
--- a/packages/zod/src/v4/classic/tests/object.test.ts
+++ b/packages/zod/src/v4/classic/tests/object.test.ts
@@ -417,7 +417,7 @@ test("passthrough index signature", () => {
   expectTypeOf<a>().toEqualTypeOf<{ a: string }>();
   const b = a.passthrough();
   type b = z.infer<typeof b>;
-  expectTypeOf<b>().toEqualTypeOf<{ a: string } & { [k: string]: unknown }>();
+  expectTypeOf<b>().toEqualTypeOf<{ a: string; [k: string]: unknown }>();
 });
 
 // test("xor", () => {
@@ -454,3 +454,23 @@ test("null prototype", () => {
   obj.a = "foo";
   expect(schema.parse(obj)).toEqual({ a: "foo" });
 });
+
+test("empty objects", () => {
+  const A = z.looseObject({});
+  type Ain = z.input<typeof A>;
+  expectTypeOf<Ain>().toEqualTypeOf<Record<string, unknown>>();
+  type Aout = z.output<typeof A>;
+  expectTypeOf<Aout>().toEqualTypeOf<Record<string, unknown>>();
+
+  const B = z.object({});
+  type Bout = z.output<typeof B>;
+  expectTypeOf<Bout>().toEqualTypeOf<Record<string, never>>();
+  type Bin = z.input<typeof B>;
+  expectTypeOf<Bin>().toEqualTypeOf<Record<string, never>>();
+
+  const C = z.strictObject({});
+  type Cout = z.output<typeof C>;
+  expectTypeOf<Cout>().toEqualTypeOf<Record<string, never>>();
+  type Cin = z.input<typeof C>;
+  expectTypeOf<Cin>().toEqualTypeOf<Record<string, never>>();
+});
diff --git a/packages/zod/src/v4/classic/tests/pickomit-object.test.ts b/packages/zod/src/v4/classic/tests/pickomit.test.ts
similarity index 98%
rename from packages/zod/src/v4/classic/tests/pickomit-object.test.ts
rename to packages/zod/src/v4/classic/tests/pickomit.test.ts
index 30a0d83b..5e8819c8 100644
--- a/packages/zod/src/v4/classic/tests/pickomit-object.test.ts
+++ b/packages/zod/src/v4/classic/tests/pickomit.test.ts
@@ -93,7 +93,7 @@ test("omit - remove optional", () => {
 test("nonstrict inference", () => {
   const laxfish = fish.pick({ name: true }).catchall(z.any());
   type laxfish = z.infer<typeof laxfish>;
-  expectTypeOf<laxfish>().toEqualTypeOf<{ name: string } & { [k: string]: any }>();
+  expectTypeOf<laxfish>().toEqualTypeOf<{ name: string; [k: string]: any }>();
 });
 
 test("nonstrict parsing - pass", () => {
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/prefault.test.ts b/packages/zod/src/v4/classic/tests/prefault.test.ts
new file mode 100644
index 00000000..72178ab6
--- /dev/null
+++ b/packages/zod/src/v4/classic/tests/prefault.test.ts
@@ -0,0 +1,37 @@
+import { expect, expectTypeOf, test } from "vitest";
+import { z } from "zod/v4";
+
+test("basic prefault", () => {
+  const a = z.prefault(z.string().trim(), "  default  ");
+  expect(a).toBeInstanceOf(z.ZodPrefault);
+  expect(a.parse("  asdf  ")).toEqual("asdf");
+  expect(a.parse(undefined)).toEqual("default");
+
+  type inp = z.input<typeof a>;
+  expectTypeOf<inp>().toEqualTypeOf<string | undefined>();
+  type out = z.output<typeof a>;
+  expectTypeOf<out>().toEqualTypeOf<string>();
+});
+
+test("prefault inside object", () => {
+  // test optinality
+  const a = z.object({
+    name: z.string().optional(),
+    age: z.number().default(1234),
+    email: z.string().prefault("1234"),
+  });
+
+  type inp = z.input<typeof a>;
+  expectTypeOf<inp>().toEqualTypeOf<{
+    name?: string | undefined;
+    age?: number | undefined;
+    email?: string | undefined;
+  }>();
+
+  type out = z.output<typeof a>;
+  expectTypeOf<out>().toEqualTypeOf<{
+    name?: string | undefined;
+    age: number;
+    email: 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/classic/tests/union.test.ts b/packages/zod/src/v4/classic/tests/union.test.ts
index 4a8ae9c2..d5ecb8e0 100644
--- a/packages/zod/src/v4/classic/tests/union.test.ts
+++ b/packages/zod/src/v4/classic/tests/union.test.ts
@@ -80,3 +80,15 @@ test("union inferred types", () => {
   type Test = z.output<typeof test>; // <— any
   expectTypeOf<Test>().toEqualTypeOf<Record<string, never> | Array<Record<string, never>>>();
 });
+
+test("union values", () => {
+  const schema = z.union([z.literal("a"), z.literal("b"), z.literal("c")]);
+
+  expect(schema._zod.values).toMatchInlineSnapshot(`
+    Set {
+      "a",
+      "b",
+      "c",
+    }
+  `);
+});
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);
+  }
+});