nextjs - ✅(Solved) Fix Logging an `AggregateError` doesn't include the `[errors]` section. [1 pull requests, 2 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#84464Fetched 2026-04-08 02:19:16
View on GitHub
Comments
2
Participants
3
Timeline
12
Reactions
0
Timeline (top)
labeled ×3commented ×2closed ×1cross-referenced ×1

Error Message

AggregateError: Multiple errors: at x (.next/server/app/api/log/route.js:1:1569)

Root Cause

// This is because the Node's util.inspect is likely patched: const formattedAggregateError = util.inspect(myAggregateError); const stringified = This is the formatted AggregateError from util.inspect, missing the \[errors]` section:\n\n${formattedAggregateError}; console.log(stringified); ``` 3. Hit enter, and observe that both console.error(myAggregateError)andconsole.log(stringified)produce a string containing the[errors]` section.

Fix Action

Fix / Workaround

// AggregateError doesn't include the errors property in the log, even in production. It does in an unpatched Node runtime. const myAggregateError = new AggregateError([error1, error2], "Multiple errors:"); console.error(myAggregateError);

// This is because the Node's util.inspect is likely patched: const formattedAggregateError = util.inspect(myAggregateError); const stringified = This is the formatted AggregateError from util.inspect, missing the \[errors]` section:\n\n${formattedAggregateError}; console.log(stringified); ``` 3. Hit enter, and observe that both console.error(myAggregateError)andconsole.log(stringified)produce a string containing the[errors]` section.

  • It looks like util.inspect is indeed patched by Next.js. This is the function that Node uses to serialize Error objects inside console.log
  • MDN reference on the errors property.
  • In development (next dev), this property is also not shown, but in development it is significantly different already (where it shows the code snippet), so it's already less comparable to expected Node behavior.
  • I've tried this in Node 24, 22, 20 and the behavior is the same in each
  • In case it's helpful, I've added a second test case to confirm that the cause property serializes correctly—it appears that it does work, and this bug is isolated to the errors property.
    • Same steps as repro, but navigate to http://localhost:3000/api/with-cause. This will log:
      AggregateError: Multiple errors:
          at x (.next/server/app/api/with-cause/route.js:1:671) {
        [cause]: Error: Root error
            at x (.next/server/app/api/with-cause/route.js:1:649)
      }

PR fix notes

PR #88999: Include AggregateError.errors in terminal output

Description (problem / solution / changelog)

Summary

This fixes a bug where Next.js overrides Node's util.inspect (to rewrite the stack trace), but that override accidentally omits the errors property of an AggregateError.

console.error(myAggregateError) now includes [errors], matching Node's behavior.

Changes

  1. Special-cased AggregateError in the util.inspect patch to maintain the errors property.
  2. Fixed a miscalculation on depth in the util.inspect patch which caused nested errors in Error.cause and AggregateError.errors to truncate in weird ways and at the wrong depth.
  3. Added unit tests which demonstrate these are now aligned to Node's util.inspect behavior.

Background

When logging an AggregateError, it should print an [errors] object.

const error1 = new Error("Error 1");
const error2 = new TypeError("Error 2");
const myAggregateError = new AggregateError([error1, error2], "Multiple errors:");

console.error(myAggregateError);
AggregateError: Multiple errors:
    at x (.next/server/app/api/log/route.js:1:1569) {
  [errors]: [
    Error: Error 1
        at x (.next/server/app/api/log/route.js:1:1569)
    TypeError: Error 2
        at x (.next/server/app/api/log/route.js:1:1588)
  ]
}

However, the [errors] object is totally omitted in Next.js production backends today:

AggregateError: Multiple errors:
    at x (.next/server/app/api/log/route.js:1:1569)

This PR ensures console.error(myAggregateError) now includes [errors], matching Node's behavior.

Are there other omissions like this?

No:

  1. Error.cause is already special-cased in the patch function.
  2. Only AggregateError needs this special treatment (and e.g., TypeError does not), because AggregateError is the only built-in error object that has its own instance property. That property is non-enumerable, so it is not handled by this logic: https://github.com/vercel/next.js/blob/f51e3acf961c9bbcab68aab6078c9267d230db21/packages/next/src/server/patch-error-inspect.ts#L465-L471

Tests

Added unit tests to test for consistency between util.inspect and the patched util.inspect. The test suite runs twice: once against the original util.inspect, and then again for the patched version of util.inspect, demonstrating they are consistent (stack trace aside).

<details> <summary>Unit test results before the bugfix (note that "Original util.inspect" tests pass, meaning the tests are aligned to default Node behavior, and the patch was breaking that behavior)</summary>
$ pnpm jest patch-error-inspect

 FAIL   Turbopack  packages/next/src/server/patch-error-inspect.test.ts
  patch-error-inspect
    Original `util.inspect`
      Regular Error
        ✓ should preserve message formatting for regular Error objects (3 ms)
        ✓ should preserve cause property for regular Error objects (1 ms)
      TypeError
        ✓ should preserve name for TypeError
      Deep Error
        ✓ should collapse deeply nested errors (1 ms)
      AggregateError
        ✓ should preserve errors property when formatting AggregateError with cause (1 ms)
        ✓ should preserve errors property when formatting empty AggregateError
    Patched `util.inspect`
      Regular Error
        ✓ should preserve message formatting for regular Error objects (2 ms)
        ✓ should preserve cause property for regular Error objects (1 ms)
      TypeError
        ✓ should preserve name for TypeError
      Deep Error
        ✕ should collapse deeply nested errors (2 ms)
      AggregateError
        ✕ should preserve errors property when formatting AggregateError with cause (1 ms)
        ✕ should preserve errors property when formatting empty AggregateError

  ● patch-error-inspect › Patched `util.inspect` › Deep Error › should collapse deeply nested errors

    expect(received).toContain(expected) // indexOf

    Expected substring: "[cause]: [Error]"
    Received string:    "Error: Depth 0 error
        at Object.<anonymous> (packages/next/src/server/patch-error-inspect.test.ts:101:32)
        at new Promise (<anonymous>) {
      [cause]: Error: Depth 1 error
          at Object.<anonymous> (packages/next/src/server/patch-error-inspect.test.ts:98:32)
          at new Promise (<anonymous>) {
        [cause]: Error: Depth 2 error
            at Object.<anonymous> (packages/next/src/server/patch-error-inspect.test.ts:95:32)
            at new Promise (<anonymous>) {
          [cause]: Error: Depth 3 error
              at Object.<anonymous> (packages/next/src/server/patch-error-inspect.test.ts:92:32)
              at new Promise (<anonymous>) {
            [cause]: Error: Depth 4 error
                at Object.<anonymous> (packages/next/src/server/patch-error-inspect.test.ts:91:32)
                at new Promise (<anonymous>)
          }
        }
      }
    }"

    

      at Object.<anonymous> (../packages/next/src/server/patch-error-inspect.test.ts:111:35)

  ● patch-error-inspect › Patched `util.inspect` › AggregateError › should preserve errors property when formatting AggregateError with cause

    expect(received).toContain(expected) // indexOf

    Expected substring: "[errors]:"
    Received string:    "AggregateError: Multiple errors:
        at Object.<anonymous> (packages/next/src/server/patch-error-inspect.test.ts:121:40)
        at new Promise (<anonymous>) {
      [cause]: Error: Root error
          at Object.<anonymous> (packages/next/src/server/patch-error-inspect.test.ts:120:35)
          at new Promise (<anonymous>)
    }"

    

      at Object.<anonymous> (../packages/next/src/server/patch-error-inspect.test.ts:129:35)

  ● patch-error-inspect › Patched `util.inspect` › AggregateError › should preserve errors property when formatting empty AggregateError

    expect(received).toContain(expected) // indexOf

    Expected substring: "[errors]:"
    Received string:    "AggregateError: No errors
        at Object.<anonymous> (packages/next/src/server/patch-error-inspect.test.ts:136:40)
        at new Promise (<anonymous>)"

    

      at Object.<anonymous> (../packages/next/src/server/patch-error-inspect.test.ts:139:35)

Test Suites: 1 failed, 1 total
Tests:       3 failed, 9 passed, 12 total
Snapshots:   0 total
Time:        0.131 s, estimated 1 s
Ran all test suites matching /patch-error-inspect/i.
</details>

Closes https://linear.app/vercel/issue/NAR-752/

Changed files

  • packages/next/src/server/patch-error-inspect.ts (modified, +7/-4)
  • test/e2e/app-dir/server-source-maps/fixtures/default/app/rsc-error-log-aggregate/page.js (added, +17/-0)
  • test/e2e/app-dir/server-source-maps/server-source-maps.test.ts (modified, +70/-0)

Code Example

const error1 = new Error("Error 1");
    const error2 = new TypeError("Error 2");

    // `AggregateError` doesn't include the `errors` property in the log, even in production. It does in an unpatched Node runtime.
    const myAggregateError = new AggregateError([error1, error2], "Multiple errors:");
    console.error(myAggregateError);

    // This is because the Node's util.inspect is likely patched:
    const formattedAggregateError = util.inspect(myAggregateError);
    const stringified = `This is the formatted AggregateError from util.inspect, missing the \`[errors]\` section:\n\n${formattedAggregateError}`;
    console.log(stringified);

---

AggregateError: Multiple errors:
    at x (.next/server/app/api/log/route.js:1:1569)

---

AggregateError: Multiple errors:
    at x (.next/server/app/api/log/route.js:1:1569) {
  [errors]: [
    Error: Error 1
        at x (.next/server/app/api/log/route.js:1:1569)
    TypeError: Error 2
        at x (.next/server/app/api/log/route.js:1:1588)
  ]
}

---

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 24.6.0: Mon Jul 14 11:28:30 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6030
  Available memory (MB): 36864
  Available CPU cores: 12
Binaries:
  Node: 22.18.0
  npm: 10.9.3
  Yarn: 1.22.22
  pnpm: 9.15.4
Relevant Packages:
  next: 15.6.0-canary.39 // Latest available version is detected (15.6.0-canary.39).
  eslint-config-next: N/A
  react: 19.1.1
  react-dom: 19.1.1
  typescript: 5.9.3
Next.js Config:
  output: N/A

---

AggregateError: Multiple errors:
        at x (.next/server/app/api/with-cause/route.js:1:671) {
      [cause]: Error: Root error
          at x (.next/server/app/api/with-cause/route.js:1:649)
    }
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/bencmbrook/next-aggregateerror-repro

To Reproduce

To reproduce:

  1. Build the app (next build / npm run build)
  2. Start the app (next start / npm run start)
  3. Open http://localhost:3000/api/log.

This will:

  • Log to the server logs: console.error(myAggregateError)
  • Display on the webpage, the result of util.inspect(myAggregateError)

The log and the text on the webpage will both show that the formatted AggregateError omits the [errors] section of the string.


To confirm that this is inconsistent with Node's behavior:

  1. In a terminal, open the Node REPL (node)

  2. Paste this code:

    const error1 = new Error("Error 1");
    const error2 = new TypeError("Error 2");
    
    // `AggregateError` doesn't include the `errors` property in the log, even in production. It does in an unpatched Node runtime.
    const myAggregateError = new AggregateError([error1, error2], "Multiple errors:");
    console.error(myAggregateError);
    
    // This is because the Node's util.inspect is likely patched:
    const formattedAggregateError = util.inspect(myAggregateError);
    const stringified = `This is the formatted AggregateError from util.inspect, missing the \`[errors]\` section:\n\n${formattedAggregateError}`;
    console.log(stringified);
  3. Hit enter, and observe that both console.error(myAggregateError) and console.log(stringified) produce a string containing the [errors] section.

Current vs. Expected behavior

Current Behavior:

console.error(myAggregateError) produces:

AggregateError: Multiple errors:
    at x (.next/server/app/api/log/route.js:1:1569)

Expected Behavior:

console.error(myAggregateError) should include the [errors] section:

AggregateError: Multiple errors:
    at x (.next/server/app/api/log/route.js:1:1569) {
  [errors]: [
    Error: Error 1
        at x (.next/server/app/api/log/route.js:1:1569)
    TypeError: Error 2
        at x (.next/server/app/api/log/route.js:1:1588)
  ]
}

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 24.6.0: Mon Jul 14 11:28:30 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6030
  Available memory (MB): 36864
  Available CPU cores: 12
Binaries:
  Node: 22.18.0
  npm: 10.9.3
  Yarn: 1.22.22
  pnpm: 9.15.4
Relevant Packages:
  next: 15.6.0-canary.39 // Latest available version is detected (15.6.0-canary.39).
  eslint-config-next: N/A
  react: 19.1.1
  react-dom: 19.1.1
  typescript: 5.9.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Route Handlers, Error Handling

Which stage(s) are affected? (Select all that apply)

Vercel (Deployed), next start (local)

Additional context

  • It looks like util.inspect is indeed patched by Next.js. This is the function that Node uses to serialize Error objects inside console.log
  • MDN reference on the errors property.
  • In development (next dev), this property is also not shown, but in development it is significantly different already (where it shows the code snippet), so it's already less comparable to expected Node behavior.
  • I've tried this in Node 24, 22, 20 and the behavior is the same in each
  • In case it's helpful, I've added a second test case to confirm that the cause property serializes correctly—it appears that it does work, and this bug is isolated to the errors property.
    • Same steps as repro, but navigate to http://localhost:3000/api/with-cause. This will log:

      AggregateError: Multiple errors:
          at x (.next/server/app/api/with-cause/route.js:1:671) {
        [cause]: Error: Root error
            at x (.next/server/app/api/with-cause/route.js:1:649)
      }

      So the cause property does serialize correctly, it's just .errors that is being omitted.

extent analysis

TL;DR

The issue can be resolved by using a custom implementation to serialize the AggregateError object, as the util.inspect function is patched by Next.js.

Guidance

  • The util.inspect function is patched by Next.js, which is causing the [errors] section to be omitted from the AggregateError object.
  • To verify the issue, compare the output of console.error(myAggregateError) in a Node REPL with the output in a Next.js application.
  • To mitigate the issue, create a custom function to serialize the AggregateError object, including the [errors] section.
  • Use the custom function to log the AggregateError object instead of relying on util.inspect.

Example

function serializeAggregateError(error) {
  const errors = error.errors.map((err) => {
    return `${err.name}: ${err.message}\n${err.stack}`;
  }).join('\n');
  return `AggregateError: ${error.message}\n${errors}`;
}

// Usage:
const myAggregateError = new AggregateError([error1, error2], "Multiple errors:");
console.log(serializeAggregateError(myAggregateError));

Notes

  • This issue is specific to Next.js and its patching of the util.inspect function.
  • The custom implementation may need to be adjusted based on the specific requirements of the application.

Recommendation

Apply a workaround by using a custom implementation to serialize the AggregateError object, as the util.inspect function is patched by Next.js and there is no clear indication of an available upgrade to fix the issue.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

nextjs - ✅(Solved) Fix Logging an `AggregateError` doesn't include the `[errors]` section. [1 pull requests, 2 comments, 3 participants]