Repository: colinhacks/zod
Pull request #4424 (2025-05-19 20:57:26)

Revert `Error` inheritance changes
This change was too breaky. While avoiding `Error` speeds up the error path for `.safeParse` by around 2.4x there are other ways to expose this behavior would without breaking everyone's snapshot tests. There's no obvious way to get `.toThrowErrorMatchingInlineSnapshot` to play nice with an error that doesn't extend `Error`.


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

> [!NOTE]
> Currently processing new changes in this PR. This may take a few minutes, please wait...
> 
> <details>
> <summary>📥 Commits</summary>
> 
> Reviewing files that changed from the base of the PR and between 538efea33eddc9e4a7b7aa3e0e7c3c839da271a9 and bc10f0bedb43908ff1c3d8d385d2e978a8ee2394.
> 
> </details>
> 
> <details>
> <summary>📒 Files selected for processing (33)</summary>
> 
> * `packages/bench/safeparse.ts` (1 hunks)
> * `packages/docs/app/layout.tsx` (2 hunks)
> * `packages/docs/content/index.mdx` (1 hunks)
> * `packages/docs/content/v4/changelog.mdx` (2 hunks)
> * `packages/docs/next.config.mjs` (0 hunks)
> * `packages/zod/src/v4/classic/errors.ts` (1 hunks)
> * `packages/zod/src/v4/classic/parse.ts` (2 hunks)
> * `packages/zod/src/v4/classic/tests/array.test.ts` (2 hunks)
> * `packages/zod/src/v4/classic/tests/async-refinements.test.ts` (2 hunks)
> * `packages/zod/src/v4/classic/tests/catch.test.ts` (1 hunks)
> * `packages/zod/src/v4/classic/tests/discriminated-unions.test.ts` (5 hunks)
> * `packages/zod/src/v4/classic/tests/enum.test.ts` (3 hunks)
> * `packages/zod/src/v4/classic/tests/error-utils.test.ts` (2 hunks)
> * `packages/zod/src/v4/classic/tests/error.test.ts` (13 hunks)
> * `packages/zod/src/v4/classic/tests/literal.test.ts` (1 hunks)
> * `packages/zod/src/v4/classic/tests/map.test.ts` (4 hunks)
> * `packages/zod/src/v4/classic/tests/nested-refine.test.ts` (1 hunks)
> * `packages/zod/src/v4/classic/tests/nonoptional.test.ts` (3 hunks)
> * `packages/zod/src/v4/classic/tests/number.test.ts` (2 hunks)
> * `packages/zod/src/v4/classic/tests/pipe.test.ts` (2 hunks)
> * `packages/zod/src/v4/classic/tests/preprocess.test.ts` (8 hunks)
> * `packages/zod/src/v4/classic/tests/primitive.test.ts` (1 hunks)
> * `packages/zod/src/v4/classic/tests/record.test.ts` (6 hunks)
> * `packages/zod/src/v4/classic/tests/set.test.ts` (3 hunks)
> * `packages/zod/src/v4/classic/tests/string.test.ts` (5 hunks)
> * `packages/zod/src/v4/classic/tests/template-literal.test.ts` (1 hunks)
> * `packages/zod/src/v4/classic/tests/transform.test.ts` (4 hunks)
> * `packages/zod/src/v4/classic/tests/tuple.test.ts` (2 hunks)
> * `packages/zod/src/v4/core/errors.ts` (2 hunks)
> * `packages/zod/src/v4/core/parse.ts` (2 hunks)
> * `packages/zod/src/v4/core/tests/index.test.ts` (1 hunks)
> * `packages/zod/src/v4/mini/tests/error.test.ts` (1 hunks)
> * `play.ts` (1 hunks)
> 
> </details>
> 
> ```ascii
>  _______________________________________________
> < Finding your faults 10 times faster than Mom. >
>  -----------------------------------------------
>   \
>    \   \
>         \ /\
>         ( )
>       .( o ).
> ```

<!-- end of auto-generated comment: review in progress by coderabbit.ai -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings
<details open="true">
<summary>🧪 Generate Unit Tests</summary>

- [ ] <!-- {"checkboxId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} -->   Create PR with Unit Tests
- [ ] <!-- {"checkboxId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} -->   Commit Unit Tests in branch `v4-extend-error`
- [ ] <!-- {"checkboxId": "07f1e7d6-8a8e-4e23-9900-8731c2c87f58", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} -->   Post Copyable Unit Tests in Comment

</details>

</details>

<!-- finishing_touch_checkbox_end -->
<!-- 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=4424):

- 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 auto-generate unit tests` to generate unit tests for 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/bench/safeparse.ts b/packages/bench/safeparse.ts
new file mode 100644
index 00000000..3527fd37
--- /dev/null
+++ b/packages/bench/safeparse.ts
@@ -0,0 +1,44 @@
+import * as z from "zod/v4";
+import { metabench } from "./metabench.js";
+
+
+
+const schema = z.object({
+  string: z.string(),
+  boolean: z.boolean(),
+  number: z.number(),
+});
+
+
+const DATA = Array.from({ length: 1000 }, () =>
+  Object.freeze({
+    // number: Math.random(),
+    // string: `${Math.random()}`,
+    // boolean: Math.random() > 0.5,
+  })
+);
+
+// console.log(z3Schema.parse(DATA[0]));
+console.log(schema.safeParse(DATA[0]));
+// console.log(v.parse(valibotSchema, DATA[0]));
+
+const bench = metabench("safeparse vs parse — fail", {
+  parse() {
+    for (const d of DATA) {
+      try{
+        const result = schema.parse(d);
+      }catch(e){
+        e;
+      }
+    }
+  },
+  safeparse() {
+    for (const d of DATA) {
+      const result = schema.safeParse(d);
+      result.error;
+    }
+  }
+
+});
+
+await bench.run();
diff --git a/packages/docs/app/layout.tsx b/packages/docs/app/layout.tsx
index f1848e8a..26ac53dd 100644
--- a/packages/docs/app/layout.tsx
+++ b/packages/docs/app/layout.tsx
@@ -4,7 +4,7 @@ import InkeepSearchBox from "@/components/inkeep-search";
 import "./global.css";
 import Scroller from "@/components/scroller";
 import { Analytics } from "@vercel/analytics/react";
-// import { Banner } from "fumadocs-ui/components/banner";
+import { Banner } from "fumadocs-ui/components/banner";
 import { RootProvider } from "fumadocs-ui/provider";
 import { Inter } from "next/font/google";
 import { type ReactNode, Suspense } from "react";
@@ -17,12 +17,12 @@ export default function Layout({ children }: { children: ReactNode }) {
   return (
     <html lang="en" className={inter.className} suppressHydrationWarning>
       <body className="flex flex-col min-h-screen">
-        {/* <Banner id="zod4">
+        <Banner id="zod4">
           💎 Zod 4 is now stable! <span>&nbsp;</span>
           <a className="underline" href="/v4">
             Read the announcement.
           </a>
-        </Banner> */}
+        </Banner>
         <InkeepBubble />
         <Analytics />
         <RootProvider
diff --git a/packages/docs/content/index.mdx b/packages/docs/content/index.mdx
index 4fa132b7..e1ffedf7 100644
--- a/packages/docs/content/index.mdx
+++ b/packages/docs/content/index.mdx
@@ -63,11 +63,11 @@ import { Bronze } from '../components/bronze';
   The age of the user. Cannot be less than 0
 </ParamField> */}
 
-{/* <div className="mt-5 font-gray-100 mx-auto text-center pt-12">
+<div className="mt-5 font-gray-100 mx-auto text-center pt-12">
   <span className="">
-    Zod 4 is now stable! <a rel="noopener noreferrer" href="/v4" alt="zod 4 release notes">Click here</a> to read the release notes.
+    Zod 4 is now stable! Read the <a rel="noopener noreferrer" href="/v4" alt="zod 4 release notes">release notes here</a>.
   </span>
-</div> */}
+</div>
 
 <br /><br /><br />
 
diff --git a/packages/docs/content/v4/changelog.mdx b/packages/docs/content/v4/changelog.mdx
index b92497f6..1c6be066 100644
--- a/packages/docs/content/v4/changelog.mdx
+++ b/packages/docs/content/v4/changelog.mdx
@@ -102,7 +102,7 @@ z.string({
 </Tab>
 </Tabs>
 
-## `.safeParse()` 
+{/* ## `.safeParse()` 
 
 For performance reasons, the errors returned by `.safeParse()` and `.safeParseAsync()` no longer extend `Error`. 
 
@@ -115,7 +115,7 @@ It is very slow to instantiate `Error` instances in JavaScript, as the initializ
 
 > Pro tip: prefer `.safeParse()` over `try/catch` in performance-sensitive code.
 
-By contrast the errors thrown by `.parse()` and `.parseAsync()` still `Error`. 
+By contrast the errors thrown by `.parse()` and `.parseAsync()` still extend `Error`. Aside from the prototype difference, the error classes are identical.
 
 ```ts
 try {
@@ -124,10 +124,48 @@ try {
   console.log(err instanceof Error); // => true
 }
 ```
-
-Aside from the prototype difference, the error classes are identical.
+ */}
 
 ## `ZodError`
+{/* 
+### changes to `.message` 
+
+Previously the `.message` property on `ZodError` was a JSON.stringified copy of the `.issues` array. This was redundant, confusing, and a bit of an abuse of the `.message` property. Also due to the [`Error` prototype changes](#safeparse) (and inconsistencies in how Node.js logs `Error` subclasses vs other objects) the logging of a multi-line `.message` property got a lot uglier:
+
+```sh
+$ tsx index.ts
+ZodError {
+  message: '[\n' +
+    '  {\n' +
+    '    "expected": "string",\n' +
+    '    "code": "invalid_type",\n' +
+    '    "path": [],\n' +
+    '    "message": "Invalid input: expected string, received number"\n' +
+    '  }\n' +
+    ']'
+}
+```
+
+
+For these reasons, the `.message` property is left empty and the `.issues` array is marked as enumerable. This keeps error logging consistent and pretty:
+
+```sh
+$ tsx index.ts
+z.string().parse(234);
+
+ZodError {
+  issues: [
+    {
+      expected: 'string',
+      code: 'invalid_type',
+      path: [],
+      message: 'Invalid input: expected string, received number'
+    }
+  ]
+}
+```
+
+Vitest uses special handling for `Error` subclasses that ignores enumerable properties.  */}
 
 ### updates issue formats
 
diff --git a/packages/docs/next.config.mjs b/packages/docs/next.config.mjs
index 8c6d4708..b6258a01 100644
--- a/packages/docs/next.config.mjs
+++ b/packages/docs/next.config.mjs
@@ -13,13 +13,7 @@ function generateRedirects(idmap, page, origin = "/") {
   const redirects = [];
 
   for (const [key, value] of Object.entries(idmap)) {
-    // if (origin === "/" && page === "/") {
-    //   console.log("skipping root redirect:", key);
-    //   continue;
-    // }
-    console.dir({ page, origin, key, value }, { depth: null });
     if (key === value && origin === page) {
-      console.log("skip infinite redirect:", key);
       continue;
     }
 
@@ -268,17 +262,7 @@ const config = {
     ];
 
     const redirects = [...mainPageRedirects, ...errorHandlingRedirects, ...changelogRedirects];
-    console.dir(redirects, { depth: null });
     return redirects;
-
-    // return [
-    //   {
-    //     source: "/",
-    //     has: [{ type: "query", key: "id", value: "basic-usage" }],
-    //     destination: "/basics?id=defining-a-schema",
-    //     permanent: true,
-    //   },
-    // ];
   },
 };
 
diff --git a/packages/zod/src/v4/classic/errors.ts b/packages/zod/src/v4/classic/errors.ts
index 04e909c2..6c95c839 100644
--- a/packages/zod/src/v4/classic/errors.ts
+++ b/packages/zod/src/v4/classic/errors.ts
@@ -4,7 +4,7 @@ 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;
 
-/** An Error-like class that doesn't extend `Error`. Used inside safeParse.  */
+/** An Error-like class used to store Zod validation issues.  */
 export interface ZodError<T = unknown> extends $ZodError<T> {
   /** @deprecated Use the `z.treeifyError(err)` function instead. */
   format(): core.$ZodFormattedError<T>;
@@ -23,6 +23,7 @@ export interface ZodError<T = unknown> extends $ZodError<T> {
 
 const initializer = (inst: ZodError, issues: core.$ZodIssue[]) => {
   $ZodError.init(inst, issues);
+  inst.name = "ZodError";
   Object.defineProperties(inst, {
     format: {
       value: (mapper: any) => core.formatError(inst, mapper),
diff --git a/packages/zod/src/v4/classic/parse.ts b/packages/zod/src/v4/classic/parse.ts
index 7f8de2a3..8304dd98 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, ZodRealError } from "./errors.js";
+import { type ZodError, ZodRealError } from "./errors.js";
 
 export type ZodSafeParseResult<T> = ZodSafeParseSuccess<T> | ZodSafeParseError<T>;
 export type ZodSafeParseSuccess<T> = { success: true; data: T; error?: never };
@@ -24,10 +24,10 @@ export const safeParse: <T extends core.$ZodType>(
   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(ZodRealError) 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(ZodRealError) as any;
diff --git a/packages/zod/src/v4/core/errors.ts b/packages/zod/src/v4/core/errors.ts
index a1b104bb..59fb738b 100644
--- a/packages/zod/src/v4/core/errors.ts
+++ b/packages/zod/src/v4/core/errors.ts
@@ -1,7 +1,7 @@
 import type { $ZodCheck, $ZodStringFormats } from "./checks.js";
 import { $constructor } from "./core.js";
 import type { $ZodType } from "./schemas.js";
-import type * as util from "./util.js";
+import * as util from "./util.js";
 
 ///////////////////////////
 ////     base type     ////
@@ -181,14 +181,25 @@ export interface $ZodError<T = unknown> extends Error {
 }
 
 const initializer = (inst: $ZodError, def: $ZodIssue[]): void => {
+  inst.name = "$ZodError";
   Object.defineProperty(inst, "_zod", {
     value: inst._zod,
     enumerable: false,
   });
   Object.defineProperty(inst, "issues", {
     value: def,
+    enumerable: false,
+  });
+  // inst.message = JSON.stringify(def, util.jsonStringifyReplacer, 2);
+  Object.defineProperty(inst, "message", {
+    get() {
+      return JSON.stringify(def, util.jsonStringifyReplacer, 2);
+    },
     enumerable: true,
+    // configurable: false,
   });
+  // inst.toString = () => inst.message;
+
   // inst.message = `Invalid input`;
   // Object.defineProperty(inst, "message", {
   //   get() {
diff --git a/packages/zod/src/v4/core/parse.ts b/packages/zod/src/v4/core/parse.ts
index 31a9e290..c96e3fc0 100644
--- a/packages/zod/src/v4/core/parse.ts
+++ b/packages/zod/src/v4/core/parse.ts
@@ -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.$ZodRealError);
 
 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.$ZodRealError);
diff --git a/play.ts b/play.ts
index e37ac636..fa74d7a0 100644
--- a/play.ts
+++ b/play.ts
@@ -1,5 +1,9 @@
-import * as z_cjs from "./node_modules/zod/dist/commonjs/v4/index.js";
-import * as z_esm from "./node_modules/zod/dist/esm/v4/index.js";
+import * as z from "zod/v4";
 
-z_cjs.string() instanceof z_esm.ZodString;
-// => true
+// console.log(z.string().safeParse(234).error);
+z.string().parse(234);
+// try {
+//   z.string().parse(234);
+// } catch (e) {
+//   console.dir(e, { depth: null });
+// }


Test patch:
diff --git a/packages/zod/src/v4/classic/tests/array.test.ts b/packages/zod/src/v4/classic/tests/array.test.ts
index dd9bed89..42982dd0 100644
--- a/packages/zod/src/v4/classic/tests/array.test.ts
+++ b/packages/zod/src/v4/classic/tests/array.test.ts
@@ -108,28 +108,26 @@ test("continue parsing despite array size error", () => {
   });
   expect(result).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_type",
-            "expected": "string",
-            "message": "Invalid input: expected string, received number",
-            "path": [
-              "people",
-              0,
-            ],
-          },
-          {
-            "code": "too_small",
-            "message": "Too small: expected array to have >2 items",
-            "minimum": 2,
-            "origin": "array",
-            "path": [
-              "people",
-            ],
-          },
+      "error": [ZodError: [
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [
+          "people",
+          0
         ],
+        "message": "Invalid input: expected string, received number"
       },
+      {
+        "origin": "array",
+        "code": "too_small",
+        "minimum": 2,
+        "path": [
+          "people"
+        ],
+        "message": "Too small: expected array to have >2 items"
+      }
+    ]],
       "success": false,
     }
   `);
@@ -141,34 +139,32 @@ test("parse should fail given sparse array", () => {
   expect(result.success).toEqual(false);
   expect(result).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_type",
-            "expected": "string",
-            "message": "Invalid input: expected string, received undefined",
-            "path": [
-              0,
-            ],
-          },
-          {
-            "code": "invalid_type",
-            "expected": "string",
-            "message": "Invalid input: expected string, received undefined",
-            "path": [
-              1,
-            ],
-          },
-          {
-            "code": "invalid_type",
-            "expected": "string",
-            "message": "Invalid input: expected string, received undefined",
-            "path": [
-              2,
-            ],
-          },
+      "error": [ZodError: [
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [
+          0
+        ],
+        "message": "Invalid input: expected string, received undefined"
+      },
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [
+          1
         ],
+        "message": "Invalid input: expected string, received undefined"
       },
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [
+          2
+        ],
+        "message": "Invalid input: expected string, received undefined"
+      }
+    ]],
       "success": false,
     }
   `);
diff --git a/packages/zod/src/v4/classic/tests/async-refinements.test.ts b/packages/zod/src/v4/classic/tests/async-refinements.test.ts
index 7d151583..ebb577ec 100644
--- a/packages/zod/src/v4/classic/tests/async-refinements.test.ts
+++ b/packages/zod/src/v4/classic/tests/async-refinements.test.ts
@@ -18,15 +18,13 @@ test("async refine", async () => {
   expect(r2.success).toBe(false);
   expect(r2).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "custom",
-            "message": "Invalid input",
-            "path": [],
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "code": "custom",
+        "path": [],
+        "message": "Invalid input"
+      }
+    ]],
       "success": false,
     }
   `);
@@ -55,15 +53,13 @@ test("async refine that uses value", async () => {
   const r1 = await schema1.safeParseAsync("asdf");
   expect(r1.success).toBe(false);
   expect(r1.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "custom",
-          "message": "Invalid input",
-          "path": [],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "code": "custom",
+        "path": [],
+        "message": "Invalid input"
+      }
+    ]]
   `);
 
   const r2 = await schema1.safeParseAsync("asdf123");
diff --git a/packages/zod/src/v4/classic/tests/catch.test.ts b/packages/zod/src/v4/classic/tests/catch.test.ts
index f613d4cd..d8ad85a6 100644
--- a/packages/zod/src/v4/classic/tests/catch.test.ts
+++ b/packages/zod/src/v4/classic/tests/catch.test.ts
@@ -230,18 +230,16 @@ test("catch error", () => {
 
   expect(result.success).toEqual(false);
   expect(result.error!).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_type",
-          "expected": "number",
-          "message": "Invalid input: expected number, received null",
-          "path": [
-            "age",
-          ],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "expected": "number",
+        "code": "invalid_type",
+        "path": [
+          "age"
+        ],
+        "message": "Invalid input: expected number, received null"
+      }
+    ]]
   `);
 });
 
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 d9179dc8..7ad121d2 100644
--- a/packages/zod/src/v4/classic/tests/discriminated-unions.test.ts
+++ b/packages/zod/src/v4/classic/tests/discriminated-unions.test.ts
@@ -149,19 +149,17 @@ test("invalid discriminator value", () => {
 
   expect(result).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_union",
-            "errors": [],
-            "message": "Invalid input",
-            "note": "No matching discriminator",
-            "path": [
-              "type",
-            ],
-          },
+      "error": [ZodError: [
+      {
+        "code": "invalid_union",
+        "errors": [],
+        "note": "No matching discriminator",
+        "path": [
+          "type"
         ],
-      },
+        "message": "Invalid input"
+      }
+    ]],
       "success": false,
     }
   `);
@@ -177,49 +175,47 @@ test("invalid discriminator value - unionFallback", () => {
     .safeParse({ type: "x", a: "abc" });
   expect(result).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_union",
-            "errors": [
-              [
-                {
-                  "code": "invalid_value",
-                  "message": "Invalid input: expected "a"",
-                  "path": [
-                    "type",
-                  ],
-                  "values": [
-                    "a",
-                  ],
-                },
+      "error": [ZodError: [
+      {
+        "code": "invalid_union",
+        "errors": [
+          [
+            {
+              "code": "invalid_value",
+              "values": [
+                "a"
               ],
-              [
-                {
-                  "code": "invalid_value",
-                  "message": "Invalid input: expected "b"",
-                  "path": [
-                    "type",
-                  ],
-                  "values": [
-                    "b",
-                  ],
-                },
-                {
-                  "code": "invalid_type",
-                  "expected": "string",
-                  "message": "Invalid input: expected string, received undefined",
-                  "path": [
-                    "b",
-                  ],
-                },
+              "path": [
+                "type"
               ],
-            ],
-            "message": "Invalid input",
-            "path": [],
-          },
+              "message": "Invalid input: expected \\"a\\""
+            }
+          ],
+          [
+            {
+              "code": "invalid_value",
+              "values": [
+                "b"
+              ],
+              "path": [
+                "type"
+              ],
+              "message": "Invalid input: expected \\"b\\""
+            },
+            {
+              "expected": "string",
+              "code": "invalid_type",
+              "path": [
+                "b"
+              ],
+              "message": "Invalid input: expected string, received undefined"
+            }
+          ]
         ],
-      },
+        "path": [],
+        "message": "Invalid input"
+      }
+    ]],
       "success": false,
     }
   `);
@@ -244,18 +240,16 @@ test("valid discriminator value, invalid data", () => {
   // ];
   expect(result).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_type",
-            "expected": "string",
-            "message": "Invalid input: expected string, received undefined",
-            "path": [
-              "a",
-            ],
-          },
+      "error": [ZodError: [
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [
+          "a"
         ],
-      },
+        "message": "Invalid input: expected string, received undefined"
+      }
+    ]],
       "success": false,
     }
   `);
@@ -333,18 +327,16 @@ test("async - invalid", async () => {
   //   },
   // ]);
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_type",
-          "expected": "string",
-          "message": "Invalid input: expected string, received number",
-          "path": [
-            "a",
-          ],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [
+          "a"
+        ],
+        "message": "Invalid input: expected string, received number"
+      }
+    ]]
   `);
 });
 
@@ -509,19 +501,17 @@ test("single element union", () => {
   expect(result).toMatchObject({ success: false });
   expect(result).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_type",
-            "expected": "string",
-            "message": "Invalid input: expected string, received undefined",
-            "path": [
-              "c",
-              "id",
-            ],
-          },
+      "error": [ZodError: [
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [
+          "c",
+          "id"
         ],
-      },
+        "message": "Invalid input: expected string, received undefined"
+      }
+    ]],
       "success": false,
     }
   `);
diff --git a/packages/zod/src/v4/classic/tests/enum.test.ts b/packages/zod/src/v4/classic/tests/enum.test.ts
index 1cc48095..144ae977 100644
--- a/packages/zod/src/v4/classic/tests/enum.test.ts
+++ b/packages/zod/src/v4/classic/tests/enum.test.ts
@@ -190,19 +190,17 @@ test("enum error message, invalid enum elementstring", () => {
   expect(result.error!.issues.length).toEqual(1);
 
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_value",
-          "message": "Invalid option: expected one of "Tuna"|"Trout"",
-          "path": [],
-          "values": [
-            "Tuna",
-            "Trout",
-          ],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "code": "invalid_value",
+        "values": [
+          "Tuna",
+          "Trout"
+        ],
+        "path": [],
+        "message": "Invalid option: expected one of \\"Tuna\\"|\\"Trout\\""
+      }
+    ]]
   `);
 });
 
@@ -212,19 +210,17 @@ test("enum error message, invalid type", () => {
   expect(result.error!.issues.length).toEqual(1);
   // expect(result.error!.issues[0].message).toEqual('Invalid input: expected one of "Tuna"|"Trout"');
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_value",
-          "message": "Invalid option: expected one of "Tuna"|"Trout"",
-          "path": [],
-          "values": [
-            "Tuna",
-            "Trout",
-          ],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "code": "invalid_value",
+        "values": [
+          "Tuna",
+          "Trout"
+        ],
+        "path": [],
+        "message": "Invalid option: expected one of \\"Tuna\\"|\\"Trout\\""
+      }
+    ]]
   `);
 });
 
@@ -238,19 +234,17 @@ test("nativeEnum default error message", () => {
   expect(result.error!.issues.length).toEqual(1);
   // expect(result.error!.issues[0].message).toEqual('Invalid input: expected one of "Tuna"|"Trout"');
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_value",
-          "message": "Invalid option: expected one of "Tuna"|"Trout"",
-          "path": [],
-          "values": [
-            "Tuna",
-            "Trout",
-          ],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "code": "invalid_value",
+        "values": [
+          "Tuna",
+          "Trout"
+        ],
+        "path": [],
+        "message": "Invalid option: expected one of \\"Tuna\\"|\\"Trout\\""
+      }
+    ]]
   `);
 });
 
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 98151ec0..d45e748b 100644
--- a/packages/zod/src/v4/classic/tests/error-utils.test.ts
+++ b/packages/zod/src/v4/classic/tests/error-utils.test.ts
@@ -14,34 +14,32 @@ const parsed = Test.safeParse({});
 test("regular error", () => {
   expect(parsed).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_type",
-            "expected": "number",
-            "message": "Invalid input: expected number, received undefined",
-            "path": [
-              "f1",
-            ],
-          },
-          {
-            "code": "invalid_type",
-            "expected": "string",
-            "message": "Invalid input: expected string, received undefined",
-            "path": [
-              "f3",
-            ],
-          },
-          {
-            "code": "invalid_type",
-            "expected": "array",
-            "message": "Invalid input: expected array, received undefined",
-            "path": [
-              "f4",
-            ],
-          },
+      "error": [ZodError: [
+      {
+        "expected": "number",
+        "code": "invalid_type",
+        "path": [
+          "f1"
         ],
+        "message": "Invalid input: expected number, received undefined"
       },
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [
+          "f3"
+        ],
+        "message": "Invalid input: expected string, received undefined"
+      },
+      {
+        "expected": "array",
+        "code": "invalid_type",
+        "path": [
+          "f4"
+        ],
+        "message": "Invalid input: expected array, received undefined"
+      }
+    ]],
       "success": false,
     }
   `);
@@ -471,7 +469,7 @@ test("inheritance", () => {
   const e1 = new z.ZodError([]);
   expect(e1).toBeInstanceOf(z.core.$ZodError);
   expect(e1).toBeInstanceOf(z.ZodError);
-  expect(e1).not.toBeInstanceOf(Error);
+  // expect(e1).not.toBeInstanceOf(Error);
 
   const e2 = new z.ZodRealError([]);
   expect(e2).toBeInstanceOf(z.ZodError);
diff --git a/packages/zod/src/v4/classic/tests/error.test.ts b/packages/zod/src/v4/classic/tests/error.test.ts
index 7071e3ec..aa14b194 100644
--- a/packages/zod/src/v4/classic/tests/error.test.ts
+++ b/packages/zod/src/v4/classic/tests/error.test.ts
@@ -47,16 +47,14 @@ test("type error with custom error map", () => {
   const result = z.string().safeParse(234, { error: errorMap });
   expect(result.success).toBe(false);
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_type",
-          "expected": "string",
-          "message": "bad type!",
-          "path": [],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [],
+        "message": "bad type!"
+      }
+    ]]
   `);
 });
 
@@ -69,18 +67,16 @@ test("refinement fail with params", () => {
     .safeParse(2, { error: errorMap });
   expect(result.success).toBe(false);
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "custom",
-          "message": "less-than-3",
-          "params": {
-            "minimum": 3,
-          },
-          "path": [],
+    [ZodError: [
+      {
+        "code": "custom",
+        "path": [],
+        "params": {
+          "minimum": 3
         },
-      ],
-    }
+        "message": "less-than-3"
+      }
+    ]]
   `);
 });
 
@@ -95,18 +91,16 @@ test("hard coded error  with custom errormap", () => {
 
   expect(result.success).toBe(false);
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "custom",
-          "message": "override",
-          "params": {
-            "minimum": 13,
-          },
-          "path": [],
+    [ZodError: [
+      {
+        "code": "custom",
+        "path": [],
+        "params": {
+          "minimum": 13
         },
-      ],
-    }
+        "message": "override"
+      }
+    ]]
   `);
 });
 
@@ -118,15 +112,13 @@ test("default error message", () => {
 
   expect(result.success).toBe(false);
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "custom",
-          "message": "Invalid input",
-          "path": [],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "code": "custom",
+        "path": [],
+        "message": "Invalid input"
+      }
+    ]]
   `);
 });
 
@@ -138,15 +130,13 @@ test("override error in refine", () => {
   expect(result.success).toBe(false);
   expect(result.error!.issues.length).toEqual(1);
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "custom",
-          "message": "override",
-          "path": [],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "code": "custom",
+        "path": [],
+        "message": "override"
+      }
+    ]]
   `);
 });
 
@@ -160,15 +150,13 @@ test("override error in refinement", () => {
   expect(result.success).toBe(false);
   expect(result.error!.issues.length).toEqual(1);
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "custom",
-          "message": "override",
-          "path": [],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "code": "custom",
+        "path": [],
+        "message": "override"
+      }
+    ]]
   `);
 });
 
@@ -182,17 +170,15 @@ test("array minimum", () => {
   expect(result.success).toBe(false);
   expect(result.error!.issues[0].code).toEqual("too_small");
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "too_small",
-          "message": "Too small: expected array to have >3 items",
-          "minimum": 3,
-          "origin": "array",
-          "path": [],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "origin": "array",
+        "code": "too_small",
+        "minimum": 3,
+        "path": [],
+        "message": "Too small: expected array to have >3 items"
+      }
+    ]]
   `);
 });
 
@@ -201,18 +187,16 @@ test("literal bigint default error message", () => {
   expect(result.success).toBe(false);
   expect(result.error!.issues.length).toEqual(1);
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_value",
-          "message": "Invalid input: expected 12n",
-          "path": [],
-          "values": [
-            12n,
-          ],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "code": "invalid_value",
+        "values": [
+          "12"
+        ],
+        "path": [],
+        "message": "Invalid input: expected 12n"
+      }
+    ]]
   `);
 });
 
@@ -230,18 +214,16 @@ test("custom path in custom error map", () => {
   const result = schema.safeParse({ items: ["first"] }, { error: errorMap });
   expect(result.success).toBe(false);
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "custom",
-          "message": "doesnt matter",
-          "path": [
-            "items",
-            "items-too-few",
-          ],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "code": "custom",
+        "path": [
+          "items",
+          "items-too-few"
+        ],
+        "message": "doesnt matter"
+      }
+    ]]
   `);
 });
 
@@ -542,17 +524,15 @@ test("z.config customError ", () => {
   const result = stringWithCustomError.min(10).safeParse("tooshort");
   expect(result.success).toBe(false);
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "too_small",
-          "message": "override",
-          "minimum": 10,
-          "origin": "string",
-          "path": [],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "origin": "string",
+        "code": "too_small",
+        "minimum": 10,
+        "path": [],
+        "message": "override"
+      }
+    ]]
   `);
   expect(result.error!.issues[0].message).toEqual("override");
   z.config({ customError: undefined });
@@ -628,26 +608,24 @@ test("dont short circuit on continuable errors", () => {
   const result = user.safeParse({ password: "asdf", confirm: "qwer" });
   expect(result.success).toBe(false);
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "too_small",
-          "message": "Too small: expected string to have >6 characters",
-          "minimum": 6,
-          "origin": "string",
-          "path": [
-            "password",
-          ],
-        },
-        {
-          "code": "custom",
-          "message": "Passwords don't match",
-          "path": [
-            "confirm",
-          ],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "origin": "string",
+        "code": "too_small",
+        "minimum": 6,
+        "path": [
+          "password"
+        ],
+        "message": "Too small: expected string to have >6 characters"
+      },
+      {
+        "code": "custom",
+        "path": [
+          "confirm"
+        ],
+        "message": "Passwords don't match"
+      }
+    ]]
   `);
   // expect(result.error!.issues.length).toEqual(2);
 });
@@ -689,7 +667,7 @@ test("error inheritance", () => {
   expect(e1).toBeInstanceOf(z.core.$ZodError);
   expect(e1).toBeInstanceOf(z.ZodError);
   expect(e1).toBeInstanceOf(z.ZodRealError);
-  expect(e1).not.toBeInstanceOf(Error);
+  // expect(e1).not.toBeInstanceOf(Error);
 
   try {
     z.string().parse(123);
@@ -697,7 +675,7 @@ test("error inheritance", () => {
     expect(e1).toBeInstanceOf(z.core.$ZodError);
     expect(e2).toBeInstanceOf(z.ZodError);
     expect(e2).toBeInstanceOf(z.ZodRealError);
-    expect(e2).toBeInstanceOf(Error);
+    // expect(e2).toBeInstanceOf(Error);
   }
 });
 
@@ -706,6 +684,15 @@ test("error serialization", () => {
     z.string().parse(123);
   } catch (e) {
     console.dir(e, { depth: null });
-    expect(e).toMatchInlineSnapshot(`[Error]`);
+    expect(e).toMatchInlineSnapshot(`
+      [ZodError: [
+        {
+          "expected": "string",
+          "code": "invalid_type",
+          "path": [],
+          "message": "Invalid input: expected string, received number"
+        }
+      ]]
+    `);
   }
 });
diff --git a/packages/zod/src/v4/classic/tests/literal.test.ts b/packages/zod/src/v4/classic/tests/literal.test.ts
index 46dd91a3..904fb514 100644
--- a/packages/zod/src/v4/classic/tests/literal.test.ts
+++ b/packages/zod/src/v4/classic/tests/literal.test.ts
@@ -60,18 +60,16 @@ test("literal default error message", () => {
   expect(result.success).toEqual(false);
   expect(result.error!.issues.length).toEqual(1);
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_value",
-          "message": "Invalid input: expected "Tuna"",
-          "path": [],
-          "values": [
-            "Tuna",
-          ],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "code": "invalid_value",
+        "values": [
+          "Tuna"
+        ],
+        "path": [],
+        "message": "Invalid input: expected \\"Tuna\\""
+      }
+    ]]
   `);
 });
 
diff --git a/packages/zod/src/v4/classic/tests/map.test.ts b/packages/zod/src/v4/classic/tests/map.test.ts
index 34e6e7a8..47c19710 100644
--- a/packages/zod/src/v4/classic/tests/map.test.ts
+++ b/packages/zod/src/v4/classic/tests/map.test.ts
@@ -32,24 +32,22 @@ test("valid parse async", async () => {
   const result = await asyncMap.safeParseAsync(new Map([["first", "foo"]]));
   expect(result.success).toEqual(false);
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "custom",
-          "message": "bad key",
-          "path": [
-            "first",
-          ],
-        },
-        {
-          "code": "custom",
-          "message": "bad value",
-          "path": [
-            "first",
-          ],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "code": "custom",
+        "path": [
+          "first"
+        ],
+        "message": "bad key"
+      },
+      {
+        "code": "custom",
+        "path": [
+          "first"
+        ],
+        "message": "bad value"
+      }
+    ]]
   `);
 });
 
@@ -68,26 +66,24 @@ test("throws when the given map has invalid key and invalid input", () => {
   if (result.success === false) {
     expect(result.error.issues.length).toEqual(2);
     expect(result.error).toMatchInlineSnapshot(`
-      ZodError {
-        "issues": [
-          {
-            "code": "invalid_type",
-            "expected": "string",
-            "message": "Invalid input: expected string, received number",
-            "path": [
-              42,
-            ],
-          },
-          {
-            "code": "invalid_type",
-            "expected": "string",
-            "message": "Invalid input: expected string, received symbol",
-            "path": [
-              42,
-            ],
-          },
-        ],
-      }
+      [ZodError: [
+        {
+          "expected": "string",
+          "code": "invalid_type",
+          "path": [
+            42
+          ],
+          "message": "Invalid input: expected string, received number"
+        },
+        {
+          "expected": "string",
+          "code": "invalid_type",
+          "path": [
+            42
+          ],
+          "message": "Invalid input: expected string, received symbol"
+        }
+      ]]
     `);
   }
 });
@@ -146,24 +142,22 @@ test("dirty", async () => {
   if (!result.success) {
     expect(result.error.issues.length).toEqual(2);
     expect(result.error).toMatchInlineSnapshot(`
-      ZodError {
-        "issues": [
-          {
-            "code": "custom",
-            "message": "Keys must be uppercase",
-            "path": [
-              "first",
-            ],
-          },
-          {
-            "code": "custom",
-            "message": "Keys must be uppercase",
-            "path": [
-              "second",
-            ],
-          },
-        ],
-      }
+      [ZodError: [
+        {
+          "code": "custom",
+          "path": [
+            "first"
+          ],
+          "message": "Keys must be uppercase"
+        },
+        {
+          "code": "custom",
+          "path": [
+            "second"
+          ],
+          "message": "Keys must be uppercase"
+        }
+      ]]
     `);
   }
 });
@@ -188,17 +182,15 @@ test("map with object keys", () => {
   const badResult = map.safeParse(badData);
   expect(badResult.success).toEqual(false);
   expect(badResult.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_type",
-          "expected": "object",
-          "message": "Invalid input: expected object, received string",
-          "path": [
-            "bad",
-          ],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "expected": "object",
+        "code": "invalid_type",
+        "path": [
+          "bad"
+        ],
+        "message": "Invalid input: expected object, received string"
+      }
+    ]]
   `);
 });
diff --git a/packages/zod/src/v4/classic/tests/nested-refine.test.ts b/packages/zod/src/v4/classic/tests/nested-refine.test.ts
index c6bd90f6..0d3401e9 100644
--- a/packages/zod/src/v4/classic/tests/nested-refine.test.ts
+++ b/packages/zod/src/v4/classic/tests/nested-refine.test.ts
@@ -40,88 +40,84 @@ test("nested refinements", () => {
   };
   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",
-            ],
-          },
+      "error": [ZodError: [
+      {
+        "origin": "string",
+        "code": "too_small",
+        "minimum": 1,
+        "path": [
+          "nested",
+          "confirm"
         ],
+        "message": "Too small: expected string to have >1 characters"
       },
+      {
+        "code": "custom",
+        "path": [
+          "nested",
+          "confirm"
+        ],
+        "message": "Confirm length should be > 2"
+      },
+      {
+        "code": "custom",
+        "path": [
+          "nested",
+          "confirm"
+        ],
+        "message": "Value must be \\"bar\\""
+      },
+      {
+        "code": "custom",
+        "path": [
+          "nested",
+          "confirm"
+        ],
+        "message": "Password and confirm must match"
+      }
+    ]],
       "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",
-            ],
-          },
+      "error": [ZodError: [
+      {
+        "origin": "string",
+        "code": "too_small",
+        "minimum": 1,
+        "path": [
+          "nested",
+          "confirm"
         ],
+        "message": "Too small: expected string to have >1 characters"
       },
+      {
+        "code": "custom",
+        "path": [
+          "nested",
+          "confirm"
+        ],
+        "message": "Confirm length should be > 2"
+      },
+      {
+        "code": "custom",
+        "path": [
+          "nested",
+          "confirm"
+        ],
+        "message": "Value must be \\"bar\\""
+      },
+      {
+        "code": "custom",
+        "path": [
+          "nested",
+          "confirm"
+        ],
+        "message": "Password and confirm must match"
+      }
+    ]],
       "success": false,
     }
   `);
diff --git a/packages/zod/src/v4/classic/tests/nonoptional.test.ts b/packages/zod/src/v4/classic/tests/nonoptional.test.ts
index 6ef30936..07f40fb0 100644
--- a/packages/zod/src/v4/classic/tests/nonoptional.test.ts
+++ b/packages/zod/src/v4/classic/tests/nonoptional.test.ts
@@ -10,16 +10,14 @@ test("nonoptional", () => {
   expect(result.success).toBe(false);
   expect(result).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_type",
-            "expected": "string",
-            "message": "Invalid input: expected string, received undefined",
-            "path": [],
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [],
+        "message": "Invalid input: expected string, received undefined"
+      }
+    ]],
       "success": false,
     }
   `);
@@ -34,16 +32,14 @@ test("nonoptional with default", () => {
   expect(result.success).toBe(false);
   expect(result).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_type",
-            "expected": "nonoptional",
-            "message": "Invalid input: expected nonoptional, received undefined",
-            "path": [],
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "code": "invalid_type",
+        "expected": "nonoptional",
+        "path": [],
+        "message": "Invalid input: expected nonoptional, received undefined"
+      }
+    ]],
       "success": false,
     }
   `);
@@ -61,34 +57,30 @@ test("nonoptional in object", () => {
   // expect(schema.safeParse({ hi: undefined }).success).toEqual(false);
   expect(r2.success).toEqual(false);
   expect(r2.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_type",
-          "expected": "nonoptional",
-          "message": "Invalid input: expected nonoptional, received undefined",
-          "path": [
-            "hi",
-          ],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "code": "invalid_type",
+        "expected": "nonoptional",
+        "path": [
+          "hi"
+        ],
+        "message": "Invalid input: expected nonoptional, received undefined"
+      }
+    ]]
   `);
 
   const r3 = schema.safeParse({});
   expect(r3.success).toEqual(false);
   expect(r3.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_type",
-          "expected": "nonoptional",
-          "message": "Invalid input: expected nonoptional, received undefined",
-          "path": [
-            "hi",
-          ],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "code": "invalid_type",
+        "expected": "nonoptional",
+        "path": [
+          "hi"
+        ],
+        "message": "Invalid input: expected nonoptional, received undefined"
+      }
+    ]]
   `);
 });
diff --git a/packages/zod/src/v4/classic/tests/number.test.ts b/packages/zod/src/v4/classic/tests/number.test.ts
index 1e9fda71..937d044c 100644
--- a/packages/zod/src/v4/classic/tests/number.test.ts
+++ b/packages/zod/src/v4/classic/tests/number.test.ts
@@ -16,33 +16,29 @@ test("Infinity validation", () => {
   const schema = z.number();
   expect(schema.safeParse(Number.POSITIVE_INFINITY)).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_type",
-            "expected": "number",
-            "message": "Invalid input: expected number, received number",
-            "path": [],
-            "received": "Infinity",
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "expected": "number",
+        "code": "invalid_type",
+        "received": "Infinity",
+        "path": [],
+        "message": "Invalid input: expected number, received number"
+      }
+    ]],
       "success": false,
     }
   `);
   expect(schema.safeParse(Number.NEGATIVE_INFINITY)).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_type",
-            "expected": "number",
-            "message": "Invalid input: expected number, received number",
-            "path": [],
-            "received": "Infinity",
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "expected": "number",
+        "code": "invalid_type",
+        "received": "Infinity",
+        "path": [],
+        "message": "Invalid input: expected number, received number"
+      }
+    ]],
       "success": false,
     }
   `);
@@ -153,33 +149,29 @@ test(".finite() validation", () => {
   expect(schema.parse(123)).toEqual(123);
   expect(schema.safeParse(Number.POSITIVE_INFINITY)).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_type",
-            "expected": "number",
-            "message": "Invalid input: expected number, received number",
-            "path": [],
-            "received": "Infinity",
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "expected": "number",
+        "code": "invalid_type",
+        "received": "Infinity",
+        "path": [],
+        "message": "Invalid input: expected number, received number"
+      }
+    ]],
       "success": false,
     }
   `);
   expect(schema.safeParse(Number.NEGATIVE_INFINITY)).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_type",
-            "expected": "number",
-            "message": "Invalid input: expected number, received number",
-            "path": [],
-            "received": "Infinity",
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "expected": "number",
+        "code": "invalid_type",
+        "received": "Infinity",
+        "path": [],
+        "message": "Invalid input: expected number, received number"
+      }
+    ]],
       "success": false,
     }
   `);
diff --git a/packages/zod/src/v4/classic/tests/pipe.test.ts b/packages/zod/src/v4/classic/tests/pipe.test.ts
index 0a338215..9bdbc7c8 100644
--- a/packages/zod/src/v4/classic/tests/pipe.test.ts
+++ b/packages/zod/src/v4/classic/tests/pipe.test.ts
@@ -40,20 +40,18 @@ test("continue on non-fatal errors", () => {
 
   expect(schema.safeParse("4321")).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "custom",
-            "message": "A",
-            "path": [],
-          },
-          {
-            "code": "custom",
-            "message": "B",
-            "path": [],
-          },
-        ],
+      "error": [ZodError: [
+      {
+        "code": "custom",
+        "path": [],
+        "message": "A"
       },
+      {
+        "code": "custom",
+        "path": [],
+        "message": "B"
+      }
+    ]],
       "success": false,
     }
   `);
@@ -70,15 +68,13 @@ test("break on fatal errors", () => {
 
   expect(schema.safeParse("4321")).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "custom",
-            "message": "A",
-            "path": [],
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "code": "custom",
+        "path": [],
+        "message": "A"
+      }
+    ]],
       "success": false,
     }
   `);
diff --git a/packages/zod/src/v4/classic/tests/preprocess.test.ts b/packages/zod/src/v4/classic/tests/preprocess.test.ts
index 305245e3..6a8faee4 100644
--- a/packages/zod/src/v4/classic/tests/preprocess.test.ts
+++ b/packages/zod/src/v4/classic/tests/preprocess.test.ts
@@ -32,15 +32,13 @@ test("ctx.addIssue accepts string", () => {
   expect(result.error!.issues).toHaveLength(1);
   expect(result).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "custom",
-            "message": "bad stuff",
-            "path": [],
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "message": "bad stuff",
+        "code": "custom",
+        "path": []
+      }
+    ]],
       "success": false,
     }
   `);
@@ -63,15 +61,13 @@ test("preprocess ctx.addIssue with parse", () => {
   expect(result.error!.issues).toHaveLength(1);
   expect(result).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "custom",
-            "message": "asdf is not one of our allowed strings",
-            "path": [],
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "code": "custom",
+        "message": "asdf is not one of our allowed strings",
+        "path": []
+      }
+    ]],
       "success": false,
     }
   `);
@@ -90,21 +86,19 @@ test("preprocess ctx.addIssue non-fatal by default", () => {
   expect(result.error!.issues).toHaveLength(2);
   expect(result).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "custom",
-            "message": "custom error",
-            "path": [],
-          },
-          {
-            "code": "invalid_type",
-            "expected": "string",
-            "message": "Invalid input: expected string, received number",
-            "path": [],
-          },
-        ],
+      "error": [ZodError: [
+      {
+        "code": "custom",
+        "message": "custom error",
+        "path": []
       },
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [],
+        "message": "Invalid input: expected string, received number"
+      }
+    ]],
       "success": false,
     }
   `);
@@ -127,17 +121,15 @@ test("preprocess ctx.addIssue fatal true", () => {
   expect(result.error!.issues).toHaveLength(1);
   expect(result).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "custom",
-            "fatal": true,
-            "message": "custom error",
-            "origin": "custom",
-            "path": [],
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "code": "custom",
+        "origin": "custom",
+        "message": "custom error",
+        "fatal": true,
+        "path": []
+      }
+    ]],
       "success": false,
     }
   `);
@@ -158,15 +150,13 @@ test("async preprocess ctx.addIssue with parseAsync", async () => {
   expect(result.error!.issues).toHaveLength(1);
   expect(result).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "custom",
-            "message": "asdf is not one of our allowed strings",
-            "path": [],
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "code": "custom",
+        "message": "asdf is not one of our allowed strings",
+        "path": []
+      }
+    ]],
       "success": false,
     }
   `);
@@ -188,21 +178,19 @@ test("z.NEVER in preprocess", () => {
   expect(result.error!.issues).toHaveLength(2);
   expect(result).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "custom",
-            "message": "bad",
-            "path": [],
-          },
-          {
-            "code": "invalid_type",
-            "expected": "number",
-            "message": "Invalid input: expected number, received object",
-            "path": [],
-          },
-        ],
+      "error": [ZodError: [
+      {
+        "code": "custom",
+        "message": "bad",
+        "path": []
       },
+      {
+        "expected": "number",
+        "code": "invalid_type",
+        "path": [],
+        "message": "Invalid input: expected number, received object"
+      }
+    ]],
       "success": false,
     }
   `);
@@ -221,29 +209,27 @@ test("preprocess as the second property of object", () => {
   expect(result.error!.issues).toHaveLength(2);
   expect(result).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "too_small",
-            "message": "Too small: expected string to have >1 characters",
-            "minimum": 1,
-            "origin": "string",
-            "path": [
-              "nonEmptyStr",
-            ],
-          },
-          {
-            "code": "too_small",
-            "inclusive": false,
-            "message": "Too small: expected number to be >0",
-            "minimum": 0,
-            "origin": "number",
-            "path": [
-              "positiveNum",
-            ],
-          },
+      "error": [ZodError: [
+      {
+        "origin": "string",
+        "code": "too_small",
+        "minimum": 1,
+        "path": [
+          "nonEmptyStr"
         ],
+        "message": "Too small: expected string to have >1 characters"
       },
+      {
+        "origin": "number",
+        "code": "too_small",
+        "minimum": 0,
+        "inclusive": false,
+        "path": [
+          "positiveNum"
+        ],
+        "message": "Too small: expected number to be >0"
+      }
+    ]],
       "success": false,
     }
   `);
@@ -260,28 +246,26 @@ test("preprocess validates with sibling errors", () => {
   expect(result.error!.issues).toHaveLength(2);
   expect(result).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_type",
-            "expected": "string",
-            "message": "Invalid input: expected string, received undefined",
-            "path": [
-              "missing",
-            ],
-          },
-          {
-            "code": "invalid_format",
-            "format": "regex",
-            "message": "Invalid string: must match pattern / asdf/",
-            "origin": "string",
-            "path": [
-              "preprocess",
-            ],
-            "pattern": "/ asdf/",
-          },
+      "error": [ZodError: [
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [
+          "missing"
         ],
+        "message": "Invalid input: expected string, received undefined"
       },
+      {
+        "origin": "string",
+        "code": "invalid_format",
+        "format": "regex",
+        "pattern": "/ asdf/",
+        "path": [
+          "preprocess"
+        ],
+        "message": "Invalid string: must match pattern / asdf/"
+      }
+    ]],
       "success": false,
     }
   `);
diff --git a/packages/zod/src/v4/classic/tests/primitive.test.ts b/packages/zod/src/v4/classic/tests/primitive.test.ts
index 9498ba10..756ddeb3 100644
--- a/packages/zod/src/v4/classic/tests/primitive.test.ts
+++ b/packages/zod/src/v4/classic/tests/primitive.test.ts
@@ -102,17 +102,15 @@ test("date schema", async () => {
   expect(() => dateSchema.parse(null)).toThrow();
   expect(await dateSchema.safeParseAsync(new Date("invalid"))).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_type",
-            "expected": "date",
-            "message": "Invalid input: expected date, received Date",
-            "path": [],
-            "received": "Invalid Date",
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "expected": "date",
+        "code": "invalid_type",
+        "received": "Invalid Date",
+        "path": [],
+        "message": "Invalid input: expected date, received Date"
+      }
+    ]],
       "success": false,
     }
   `);
diff --git a/packages/zod/src/v4/classic/tests/record.test.ts b/packages/zod/src/v4/classic/tests/record.test.ts
index b8b40b39..050f39b9 100644
--- a/packages/zod/src/v4/classic/tests/record.test.ts
+++ b/packages/zod/src/v4/classic/tests/record.test.ts
@@ -34,35 +34,31 @@ test("enum exhaustiveness", () => {
 
   expect(schema.safeParse({ Tuna: "asdf", Salmon: "asdf", Trout: "asdf" })).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "unrecognized_keys",
-            "keys": [
-              "Trout",
-            ],
-            "message": "Unrecognized key: "Trout"",
-            "path": [],
-          },
+      "error": [ZodError: [
+      {
+        "code": "unrecognized_keys",
+        "keys": [
+          "Trout"
         ],
-      },
+        "path": [],
+        "message": "Unrecognized key: \\"Trout\\""
+      }
+    ]],
       "success": false,
     }
   `);
   expect(schema.safeParse({ Tuna: "asdf" })).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_type",
-            "expected": "string",
-            "message": "Invalid input: expected string, received undefined",
-            "path": [
-              "Salmon",
-            ],
-          },
+      "error": [ZodError: [
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [
+          "Salmon"
         ],
-      },
+        "message": "Invalid input: expected string, received undefined"
+      }
+    ]],
       "success": false,
     }
   `);
@@ -77,35 +73,31 @@ test("literal exhaustiveness", () => {
 
   expect(schema.safeParse({ Tuna: "asdf", Salmon: "asdf", Trout: "asdf" })).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "unrecognized_keys",
-            "keys": [
-              "Trout",
-            ],
-            "message": "Unrecognized key: "Trout"",
-            "path": [],
-          },
+      "error": [ZodError: [
+      {
+        "code": "unrecognized_keys",
+        "keys": [
+          "Trout"
         ],
-      },
+        "path": [],
+        "message": "Unrecognized key: \\"Trout\\""
+      }
+    ]],
       "success": false,
     }
   `);
   expect(schema.safeParse({ Tuna: "asdf" })).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_type",
-            "expected": "string",
-            "message": "Invalid input: expected string, received undefined",
-            "path": [
-              "Salmon",
-            ],
-          },
+      "error": [ZodError: [
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [
+          "Salmon"
         ],
-      },
+        "message": "Invalid input: expected string, received undefined"
+      }
+    ]],
       "success": false,
     }
   `);
@@ -120,35 +112,31 @@ test("pipe exhaustiveness", () => {
 
   expect(schema.safeParse({ Tuna: "asdf", Salmon: "asdf", Trout: "asdf" })).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "unrecognized_keys",
-            "keys": [
-              "Trout",
-            ],
-            "message": "Unrecognized key: "Trout"",
-            "path": [],
-          },
+      "error": [ZodError: [
+      {
+        "code": "unrecognized_keys",
+        "keys": [
+          "Trout"
         ],
-      },
+        "path": [],
+        "message": "Unrecognized key: \\"Trout\\""
+      }
+    ]],
       "success": false,
     }
   `);
   expect(schema.safeParse({ Tuna: "asdf" })).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_type",
-            "expected": "string",
-            "message": "Invalid input: expected string, received undefined",
-            "path": [
-              "Salmon",
-            ],
-          },
+      "error": [ZodError: [
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [
+          "Salmon"
         ],
-      },
+        "message": "Invalid input: expected string, received undefined"
+      }
+    ]],
       "success": false,
     }
   `);
@@ -163,35 +151,31 @@ test("union exhaustiveness", () => {
 
   expect(schema.safeParse({ Tuna: "asdf", Salmon: "asdf", Trout: "asdf" })).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "unrecognized_keys",
-            "keys": [
-              "Trout",
-            ],
-            "message": "Unrecognized key: "Trout"",
-            "path": [],
-          },
+      "error": [ZodError: [
+      {
+        "code": "unrecognized_keys",
+        "keys": [
+          "Trout"
         ],
-      },
+        "path": [],
+        "message": "Unrecognized key: \\"Trout\\""
+      }
+    ]],
       "success": false,
     }
   `);
   expect(schema.safeParse({ Tuna: "asdf" })).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_type",
-            "expected": "string",
-            "message": "Invalid input: expected string, received undefined",
-            "path": [
-              "Salmon",
-            ],
-          },
+      "error": [ZodError: [
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [
+          "Salmon"
         ],
-      },
+        "message": "Invalid input: expected string, received undefined"
+      }
+    ]],
       "success": false,
     }
   `);
@@ -208,16 +192,14 @@ test("string record parse - pass", () => {
   expect(schema.safeParse({ asdf: 1234 }).success).toEqual(false);
   expect(schema.safeParse("asdf")).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_type",
-            "expected": "record",
-            "message": "Invalid input: expected record, received string",
-            "path": [],
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "expected": "record",
+        "code": "invalid_type",
+        "path": [],
+        "message": "Invalid input: expected record, received string"
+      }
+    ]],
       "success": false,
     }
   `);
@@ -325,28 +307,26 @@ test("async parsing", async () => {
   const result = await schema.safeParseAsync(data);
   expect(result.success).toEqual(false);
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "custom",
-          "message": "Invalid input",
-          "path": [
-            "foo",
-          ],
-        },
-        {
-          "code": "custom",
-          "message": "Invalid input",
-          "path": [
-            "baz",
-          ],
-        },
-        {
-          "code": "custom",
-          "message": "Invalid input",
-          "path": [],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "code": "custom",
+        "path": [
+          "foo"
+        ],
+        "message": "Invalid input"
+      },
+      {
+        "code": "custom",
+        "path": [
+          "baz"
+        ],
+        "message": "Invalid input"
+      },
+      {
+        "code": "custom",
+        "path": [],
+        "message": "Invalid input"
+      }
+    ]]
   `);
 });
diff --git a/packages/zod/src/v4/classic/tests/set.test.ts b/packages/zod/src/v4/classic/tests/set.test.ts
index 002d47ec..5baaf2e0 100644
--- a/packages/zod/src/v4/classic/tests/set.test.ts
+++ b/packages/zod/src/v4/classic/tests/set.test.ts
@@ -94,16 +94,14 @@ test("throws when a Map is given", () => {
   const result = stringSet.safeParse(new Map([]));
   expect(result.success).toEqual(false);
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_type",
-          "expected": "set",
-          "message": "Invalid input: expected set, received Map",
-          "path": [],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "expected": "set",
+        "code": "invalid_type",
+        "path": [],
+        "message": "Invalid input: expected set, received Map"
+      }
+    ]]
   `);
 });
 
@@ -112,16 +110,14 @@ test("throws when the given set has invalid input", () => {
   expect(result.success).toEqual(false);
   expect(result.error!.issues.length).toEqual(1);
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_type",
-          "expected": "string",
-          "message": "Invalid input: expected string, received symbol",
-          "path": [],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [],
+        "message": "Invalid input: expected string, received symbol"
+      }
+    ]]
   `);
 });
 
@@ -130,22 +126,20 @@ test("throws when the given set has multiple invalid entries", () => {
   expect(result.success).toEqual(false);
   expect(result.error!.issues.length).toEqual(2);
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_type",
-          "expected": "string",
-          "message": "Invalid input: expected string, received number",
-          "path": [],
-        },
-        {
-          "code": "invalid_type",
-          "expected": "string",
-          "message": "Invalid input: expected string, received number",
-          "path": [],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [],
+        "message": "Invalid input: expected string, received number"
+      },
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [],
+        "message": "Invalid input: expected string, received number"
+      }
+    ]]
   `);
 });
 
diff --git a/packages/zod/src/v4/classic/tests/string.test.ts b/packages/zod/src/v4/classic/tests/string.test.ts
index 94f3c944..125b5ad4 100644
--- a/packages/zod/src/v4/classic/tests/string.test.ts
+++ b/packages/zod/src/v4/classic/tests/string.test.ts
@@ -393,18 +393,16 @@ test("nanoid", () => {
 
   expect(result.error!.issues[0].message).toEqual("custom error");
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_format",
-          "format": "nanoid",
-          "message": "custom error",
-          "origin": "string",
-          "path": [],
-          "pattern": "/^[a-zA-Z0-9_-]{21}$/",
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "origin": "string",
+        "code": "invalid_format",
+        "format": "nanoid",
+        "pattern": "/^[a-zA-Z0-9_-]{21}$/",
+        "path": [],
+        "message": "custom error"
+      }
+    ]]
   `);
 });
 
@@ -416,18 +414,16 @@ test("bad nanoid", () => {
 
   expect(result.error!.issues[0].message).toEqual("custom error");
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_format",
-          "format": "nanoid",
-          "message": "custom error",
-          "origin": "string",
-          "path": [],
-          "pattern": "/^[a-zA-Z0-9_-]{21}$/",
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "origin": "string",
+        "code": "invalid_format",
+        "format": "nanoid",
+        "pattern": "/^[a-zA-Z0-9_-]{21}$/",
+        "path": [],
+        "message": "custom error"
+      }
+    ]]
   `);
 });
 
@@ -501,18 +497,16 @@ test("cuid", () => {
 
   expect(result.error!.issues[0].message).toEqual("Invalid cuid");
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_format",
-          "format": "cuid",
-          "message": "Invalid cuid",
-          "origin": "string",
-          "path": [],
-          "pattern": "/^[cC][^\\s-]{8,}$/",
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "origin": "string",
+        "code": "invalid_format",
+        "format": "cuid",
+        "pattern": "/^[cC][^\\\\s-]{8,}$/",
+        "path": [],
+        "message": "Invalid cuid"
+      }
+    ]]
   `);
 });
 
@@ -552,18 +546,16 @@ test("ulid", () => {
 
   expect(result.error!.issues[0].message).toEqual("Invalid ULID");
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_format",
-          "format": "ulid",
-          "message": "Invalid ULID",
-          "origin": "string",
-          "path": [],
-          "pattern": "/^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/",
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "origin": "string",
+        "code": "invalid_format",
+        "format": "ulid",
+        "pattern": "/^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/",
+        "path": [],
+        "message": "Invalid ULID"
+      }
+    ]]
   `);
 });
 
@@ -575,18 +567,16 @@ test("xid", () => {
 
   expect(result.error!.issues[0].message).toEqual("Invalid XID");
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_format",
-          "format": "xid",
-          "message": "Invalid XID",
-          "origin": "string",
-          "path": [],
-          "pattern": "/^[0-9a-vA-V]{20}$/",
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "origin": "string",
+        "code": "invalid_format",
+        "format": "xid",
+        "pattern": "/^[0-9a-vA-V]{20}$/",
+        "path": [],
+        "message": "Invalid XID"
+      }
+    ]]
   `);
 });
 
diff --git a/packages/zod/src/v4/classic/tests/template-literal.test.ts b/packages/zod/src/v4/classic/tests/template-literal.test.ts
index c4da0546..e46dccdf 100644
--- a/packages/zod/src/v4/classic/tests/template-literal.test.ts
+++ b/packages/zod/src/v4/classic/tests/template-literal.test.ts
@@ -686,82 +686,72 @@ test("template literal parsing - failure - complex cases", () => {
 test("template literal parsing - failure - issue format", () => {
   expect(anotherNull.safeParse("1null")).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_format",
-            "format": "template_literal",
-            "message": "Invalid input",
-            "path": [],
-            "pattern": "^null$",
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "code": "invalid_format",
+        "format": "template_literal",
+        "pattern": "^null$",
+        "path": [],
+        "message": "Invalid input"
+      }
+    ]],
       "success": false,
     }
   `);
   expect(cuidZZZ.safeParse("1cjld2cyuq0000t3rmniod1foyZZZ")).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_format",
-            "format": "template_literal",
-            "message": "Invalid input",
-            "path": [],
-            "pattern": "^[cC][^\\s-]{8,}ZZZ$",
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "code": "invalid_format",
+        "format": "template_literal",
+        "pattern": "^[cC][^\\\\s-]{8,}ZZZ$",
+        "path": [],
+        "message": "Invalid input"
+      }
+    ]],
       "success": false,
     }
   `);
   expect(stringMin5Max10.safeParse("1234")).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_format",
-            "format": "template_literal",
-            "message": "Invalid input",
-            "path": [],
-            "pattern": "^[\\s\\S]{5,10}$",
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "code": "invalid_format",
+        "format": "template_literal",
+        "pattern": "^[\\\\s\\\\S]{5,10}$",
+        "path": [],
+        "message": "Invalid input"
+      }
+    ]],
       "success": false,
     }
   `);
   expect(connectionString.safeParse("mongodb://host:1234/defaultauthdb?authSourceadmin")).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_format",
-            "format": "template_literal",
-            "message": "Invalid input",
-            "path": [],
-            "pattern": "^mongodb:\\/\\/(\\w+:\\w+@)?\\w+:\\d+(\\/(\\w+)?(\\?(\\w+=\\w+(&\\w+=\\w+)*)?)?)?$",
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "code": "invalid_format",
+        "format": "template_literal",
+        "pattern": "^mongodb:\\\\/\\\\/(\\\\w+:\\\\w+@)?\\\\w+:\\\\d+(\\\\/(\\\\w+)?(\\\\?(\\\\w+=\\\\w+(&\\\\w+=\\\\w+)*)?)?)?$",
+        "path": [],
+        "message": "Invalid input"
+      }
+    ]],
       "success": false,
     }
   `);
 
   expect(stringStartsWithMax5.safeParse("1hell")).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "invalid_format",
-            "format": "template_literal",
-            "message": "Invalid input",
-            "path": [],
-            "pattern": "^hello.*$",
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "code": "invalid_format",
+        "format": "template_literal",
+        "pattern": "^hello.*$",
+        "path": [],
+        "message": "Invalid input"
+      }
+    ]],
       "success": false,
     }
   `);
diff --git a/packages/zod/src/v4/classic/tests/transform.test.ts b/packages/zod/src/v4/classic/tests/transform.test.ts
index a8a1edf8..ce8749fc 100644
--- a/packages/zod/src/v4/classic/tests/transform.test.ts
+++ b/packages/zod/src/v4/classic/tests/transform.test.ts
@@ -17,15 +17,13 @@ test("transform ctx.addIssue with parse", () => {
   const result = schema.safeParse("asdf");
   expect(result.success).toEqual(false);
   expect(result.error!).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "custom",
-          "message": "asdf is not one of our allowed strings",
-          "path": [],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "code": "custom",
+        "message": "asdf is not one of our allowed strings",
+        "path": []
+      }
+    ]]
   `);
 });
 
@@ -49,15 +47,13 @@ test("transform ctx.addIssue with parseAsync", async () => {
 
   expect(result).toMatchInlineSnapshot(`
     {
-      "error": ZodError {
-        "issues": [
-          {
-            "code": "custom",
-            "message": "asdf is not one of our allowed strings",
-            "path": [],
-          },
-        ],
-      },
+      "error": [ZodError: [
+      {
+        "code": "custom",
+        "message": "asdf is not one of our allowed strings",
+        "path": []
+      }
+    ]],
       "success": false,
     }
   `);
@@ -204,15 +200,13 @@ test("short circuit on dirty", () => {
   expect(result.success).toEqual(false);
 
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "custom",
-          "message": "Invalid input",
-          "path": [],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "code": "custom",
+        "path": [],
+        "message": "Invalid input"
+      }
+    ]]
   `);
 
   const result2 = schema.safeParse(1234);
@@ -231,30 +225,26 @@ test("async short circuit on dirty", async () => {
   expect(result.success).toEqual(false);
 
   expect(result.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "custom",
-          "message": "Invalid input",
-          "path": [],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "code": "custom",
+        "path": [],
+        "message": "Invalid input"
+      }
+    ]]
   `);
 
   const result2 = await schema.spa(1234);
   expect(result2.success).toEqual(false);
 
   expect(result2.error).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_type",
-          "expected": "string",
-          "message": "Invalid input: expected string, received number",
-          "path": [],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "expected": "string",
+        "code": "invalid_type",
+        "path": [],
+        "message": "Invalid input: expected string, received number"
+      }
+    ]]
   `);
 });
diff --git a/packages/zod/src/v4/classic/tests/tuple.test.ts b/packages/zod/src/v4/classic/tests/tuple.test.ts
index 3a4e50c8..94291f1e 100644
--- a/packages/zod/src/v4/classic/tests/tuple.test.ts
+++ b/packages/zod/src/v4/classic/tests/tuple.test.ts
@@ -11,49 +11,43 @@ test("successful validation", () => {
   const r1 = testTuple.safeParse(["asdf", "asdf"]);
   expect(r1.success).toEqual(false);
   expect(r1.error!).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_type",
-          "expected": "number",
-          "message": "Invalid input: expected number, received string",
-          "path": [
-            1,
-          ],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "expected": "number",
+        "code": "invalid_type",
+        "path": [
+          1
+        ],
+        "message": "Invalid input: expected number, received string"
+      }
+    ]]
   `);
 
   const r2 = testTuple.safeParse(["asdf", 1234, true]);
   expect(r2.success).toEqual(false);
   expect(r2.error!).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "too_big",
-          "maximum": 2,
-          "message": "Too big: expected array to have <2 items",
-          "origin": "array",
-          "path": [],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "origin": "array",
+        "code": "too_big",
+        "maximum": 2,
+        "path": [],
+        "message": "Too big: expected array to have <2 items"
+      }
+    ]]
   `);
 
   const r3 = testTuple.safeParse({});
   expect(r3.success).toEqual(false);
   expect(r3.error!).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_type",
-          "expected": "tuple",
-          "message": "Invalid input: expected tuple, received object",
-          "path": [],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "expected": "tuple",
+        "code": "invalid_type",
+        "path": [],
+        "message": "Invalid input: expected tuple, received object"
+      }
+    ]]
   `);
 });
 
@@ -69,49 +63,43 @@ test("async validation", async () => {
   const r1 = await testTuple.safeParseAsync(["asdf", "asdf"]);
   expect(r1.success).toEqual(false);
   expect(r1.error!).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_type",
-          "expected": "number",
-          "message": "Invalid input: expected number, received string",
-          "path": [
-            1,
-          ],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "expected": "number",
+        "code": "invalid_type",
+        "path": [
+          1
+        ],
+        "message": "Invalid input: expected number, received string"
+      }
+    ]]
   `);
 
   const r2 = await testTuple.safeParseAsync(["asdf", 1234, true]);
   expect(r2.success).toEqual(false);
   expect(r2.error!).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "too_big",
-          "maximum": 2,
-          "message": "Too big: expected array to have <2 items",
-          "origin": "array",
-          "path": [],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "origin": "array",
+        "code": "too_big",
+        "maximum": 2,
+        "path": [],
+        "message": "Too big: expected array to have <2 items"
+      }
+    ]]
   `);
 
   const r3 = await testTuple.safeParseAsync({});
   expect(r3.success).toEqual(false);
   expect(r3.error!).toMatchInlineSnapshot(`
-    ZodError {
-      "issues": [
-        {
-          "code": "invalid_type",
-          "expected": "tuple",
-          "message": "Invalid input: expected tuple, received object",
-          "path": [],
-        },
-      ],
-    }
+    [ZodError: [
+      {
+        "expected": "tuple",
+        "code": "invalid_type",
+        "path": [],
+        "message": "Invalid input: expected tuple, received object"
+      }
+    ]]
   `);
 });
 
diff --git a/packages/zod/src/v4/core/tests/index.test.ts b/packages/zod/src/v4/core/tests/index.test.ts
index 05a11776..bc9a7bd9 100644
--- a/packages/zod/src/v4/core/tests/index.test.ts
+++ b/packages/zod/src/v4/core/tests/index.test.ts
@@ -1,5 +1,46 @@
-import { expect, test } from "vitest";
+import { expect, expectTypeOf, test } from "vitest";
+import * as z from "zod/v3";
 
 test("test", () => {
   expect(true).toBe(true);
 });
+
+test("test2", () => {
+  expect(() => z.string().parse(234)).toThrowErrorMatchingInlineSnapshot(`
+    [ZodError: [
+      {
+        "code": "invalid_type",
+        "expected": "string",
+        "received": "number",
+        "path": [],
+        "message": "Expected string, received number"
+      }
+    ]]
+  `);
+});
+
+test("async validation", async () => {
+  const testTuple = z
+    .tuple([z.string().refine(async () => true), z.number().refine(async () => true)])
+    .refine(async () => true);
+  expectTypeOf<typeof testTuple._output>().toEqualTypeOf<[string, number]>();
+
+  const val = await testTuple.parseAsync(["asdf", 1234]);
+  expect(val).toEqual(val);
+
+  const r1 = await testTuple.safeParseAsync(["asdf", "asdf"]);
+  expect(r1.success).toEqual(false);
+  expect(r1.error!).toMatchInlineSnapshot(`
+    [ZodError: [
+      {
+        "code": "invalid_type",
+        "expected": "number",
+        "received": "string",
+        "path": [
+          1
+        ],
+        "message": "Expected number, received string"
+      }
+    ]]
+  `);
+});
diff --git a/packages/zod/src/v4/mini/tests/error.test.ts b/packages/zod/src/v4/mini/tests/error.test.ts
index d6267b73..1ed5aec6 100644
--- a/packages/zod/src/v4/mini/tests/error.test.ts
+++ b/packages/zod/src/v4/mini/tests/error.test.ts
@@ -11,7 +11,7 @@ test("no locale by default", () => {
 test("error inheritance", () => {
   const e1 = z.string().safeParse(123).error!;
   expect(e1).toBeInstanceOf(z.core.$ZodError);
-  expect(e1).not.toBeInstanceOf(Error);
+  // expect(e1).not.toBeInstanceOf(Error);
 
   try {
     z.string().parse(123);