Skip to content

fix(core): make AxiosError cause non-enumerable to prevent circular JSON errors - #10913

Merged
jasonsaayman merged 5 commits into
axios:v1.xfrom
webdevelopersrinu:fix/axioserror-cause-non-enumerable
Jun 14, 2026
Merged

jasonsaayman merged 5 commits into
axios:v1.xfrom
webdevelopersrinu:fix/axioserror-cause-non-enumerable

Conversation

@webdevelopersrinu

@webdevelopersrinu webdevelopersrinu commented May 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Since #6982, AxiosError.from() set cause as an enumerable own property. Native Error cause (per spec, new Error(msg, { cause })) is non-enumerable. Because the wrapped error routinely holds circular internals (sockets, requests, agents), an enumerable cause makes structured loggers (pino/winston/bunyan) and any own-property walk throw Converting circular structure to JSON. Regression since v1.12.0 (last good: v1.11.0).

Repro:
```js
axios.get('http://nonexistent.invalid').catch(e =>
JSON.stringify(Object.fromEntries(Object.entries(e))) // throws
);
```

Linked issue

Closes #7205

Changes

  • lib/core/AxiosError.js: define cause as non-enumerable (matches native Error; mirrors the existing message descriptor incl. __proto__: null).
  • lib/adapters/fetch.js: same fix on the fetch cancel-error cause path.
  • tests/unit/core/AxiosError.test.js: regression tests — non-enumerable, still accessible, logger-style walk no longer throws, toJSON() output unchanged.

cause remains fully accessible for debugging. Serialized output is unchanged (toJSON() already excluded cause). No public API change → no .d.ts updates. No new deps. 78/78 focused unit tests + lint green locally.

Checklist

  • Tests added or updated (or N/A with reason)
  • Docs / types updated if public API changed (N/A — no public API change)
  • No breaking changes (cause stays accessible; aligns with native Error spec)

Summary by cubic

Make AxiosError.cause non-enumerable to match native Error and prevent circular JSON errors in structured loggers. Applied in AxiosError.from(), and in fetch adapter cancel and network-error paths; cause stays accessible and toJSON() is unchanged.

Description

  • Summary of changes

    • Define non-enumerable cause in AxiosError.from().
    • Fetch adapter: set non-enumerable cause for cancel and network errors (replace Object.assign with Object.defineProperty).
  • Reasoning

    • Prevent “Converting circular structure to JSON” when loggers walk enumerable props.
    • Align with native Error semantics; fixes regression since v1.12.0.
  • Additional context

Docs

Update /docs/ error handling guide to note AxiosError.cause is non-enumerable and add a tip about logger/serialization behavior.

Testing

  • Added unit tests:
    • Core: AxiosError.from() sets non-enumerable cause, remains accessible, excluded from toJSON(), and safe for own-property serialization.
    • Fetch adapter: canceled and network-error branches assert cause is non-enumerable and safe for logger-style serialization.
  • No further tests needed.

Semantic version impact

Patch: bug fix with no public API change.

Written for commit a7a5541. Summary will update on new commits.

Review in cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 3 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Re-trigger cubic

@jasonsaayman jasonsaayman left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In tests/unit/adapters/fetch.test.js:742 the existing fetch network-error test only checks err.cause.code; it should also assert Object.getOwnPropertyDescriptor(err, 'cause').enumerable === false and that own-property serialisation does not throw. The new core tests do not cover the fetch adapter’s manual Object.assign path.

Comment thread lib/adapters/fetch.js Resolved
@jasonsaayman jasonsaayman added the status::changes-requested A reviewer requested changes to the PR label May 24, 2026
webdevelopersrinu added a commit to webdevelopersrinu/axios that referenced this pull request May 25, 2026
Addresses review on axios#10913: the fetch network-error branch built its AxiosError with Object.assign(err, { cause }), which kept cause enumerable and could reproduce the same circular-serialization failure. Use the same non-enumerable descriptor here, and assert enumerable === false in the fetch adapter tests.
@webdevelopersrinu

Copy link
Copy Markdown
Contributor Author

Thank you for the careful review and for pointing this out — you're right, I had missed that path. I've addressed it in 4ba480a: the network-error branch now constructs the AxiosError and sets cause using the same non-enumerable Object.defineProperty descriptor instead of Object.assign, so the fetch adapter's manual path no longer leaves an enumerable circular cause.

I've also extended the tests as you suggested: the existing network-error test now asserts Object.getOwnPropertyDescriptor(err, 'cause').enumerable === false, and I added a deterministic test (an injected failing fetch with a circular cause) confirming cause remains accessible, is non-enumerable, and that an own-property walk no longer throws.

Please let me know if you'd like any changes to the approach — happy to adjust. Thanks again for your time and guidance.

webdevelopersrinu and others added 3 commits June 11, 2026 19:14
…SON errors

Since axios#6982, AxiosError.from() set `cause` as an enumerable own property. Native Error `cause` (per spec, via new Error(msg,{cause})) is non-enumerable. Because the wrapped error routinely holds circular internals (sockets, requests, agents), an enumerable `cause` makes structured loggers (pino/winston) and any own-property walk throw "Converting circular structure to JSON". Regression introduced in v1.12.0.

Fix: define `cause` as non-enumerable (matching native Error) in AxiosError.from() and the fetch adapter cancel path. `cause` stays fully accessible for debugging; serialized output is unchanged (toJSON already excludes it). Adds regression tests.

Closes axios#7205
Addresses review on axios#10913: the fetch network-error branch built its AxiosError with Object.assign(err, { cause }), which kept cause enumerable and could reproduce the same circular-serialization failure. Use the same non-enumerable descriptor here, and assert enumerable === false in the fetch adapter tests.
@jasonsaayman
jasonsaayman force-pushed the fix/axioserror-cause-non-enumerable branch from 4ba480a to cafc3d6 Compare June 11, 2026 17:23
@jasonsaayman
jasonsaayman self-requested a review June 11, 2026 17:24

@jasonsaayman jasonsaayman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jasonsaayman jasonsaayman removed the status::changes-requested A reviewer requested changes to the PR label Jun 11, 2026
@jasonsaayman jasonsaayman added the commit::fix The PR is related to a bugfix label Jun 14, 2026
@jasonsaayman
jasonsaayman merged commit 4918457 into axios:v1.x Jun 14, 2026
26 checks passed
leuwen-lc pushed a commit to leuwen-lc/rhdemo that referenced this pull request Jul 9, 2026
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [axios](https://axios-http.com) ([source](https://github.com/axios/axios)) | [`1.18.0` → `1.18.1`](https://renovatebot.com/diffs/npm/axios/1.18.0/1.18.1) | ![age](https://developer.mend.io/api/mc/badges/age/npm/axios/1.18.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/axios/1.18.0/1.18.1?slim=true) |

---

### Release Notes

<details>
<summary>axios/axios (axios)</summary>

### [`v1.18.1`](https://github.com/axios/axios/releases/tag/v1.18.1)

[Compare Source](axios/axios@v1.18.0...v1.18.1)

#### v1.18.1 — June 21, 2026

This release focuses on Node HTTP adapter fixes, safer AxiosError serialisation, runtime/type correctness fixes, documentation updates, and dependency maintenance.

#### 🐛 Bug Fixes

- AxiosError Serialisation: Made AxiosError#cause non-enumerable to prevent circular JSON serialisation failures when errors include nested causes. ([#&#8203;10913](axios/axios#10913))
- Node HTTP Adapter: Guarded socket.setKeepAlive for proxy agent streams, accepted path-only URLs when socketPath is configured, deferred environment proxy handling to Node, and explicitly passed maxBodyLength through to follow-redirects. ([#&#8203;10917](axios/axios#10917), [#&#8203;10930](axios/axios#10930), [#&#8203;10942](axios/axios#10942), [#&#8203;10993](axios/axios#10993))
- Runtime and Type Correctness: Fixed several runtime crashes, type definition mismatches, and incorrect error handling paths. ([#&#8203;10959](axios/axios#10959), [#&#8203;11021](axios/axios#11021))
- AxiosURLSearchParams: Switched the encoder callback to an arrow function so `encoder.call(this)` receives the `AxiosURLSearchParams` instance correctly. ([#&#8203;11019](axios/axios#11019))

#### 🔧 Maintenance & Chores

- Documentation: Documented sensitive headers and status transition behaviour, prepared cleaned-up docs, added Deno install instructions, and clarified that request data is request-specific ([#&#8203;11007](axios/axios#11007), [#&#8203;11010](axios/axios#11010), [#&#8203;11023](axios/axios#11023), [#&#8203;11025](axios/axios#11025))

- Dependencies: Bumped vite, rollup, form-data, js-yaml, and multer across the root project, docs, smoke tests, and module test workspaces. ([#&#8203;11011](axios/axios#11011), [#&#8203;11012](axios/axios#11012), [#&#8203;11013](axios/axios#11013), [#&#8203;11014](axios/axios#11014), [#&#8203;11015](axios/axios#11015), [#&#8203;11016](axios/axios#11016), [#&#8203;11017](axios/axios#11017), [#&#8203;11026](axios/axios#11026))

#### 🌟 New Contributors

We are thrilled to welcome our new contributors. Thank you for helping improve axios:

- [@&#8203;webdevelopersrinu](https://github.com/webdevelopersrinu) ([#&#8203;10913](axios/axios#10913))
- [@&#8203;sijie-Z](https://github.com/sijie-Z) ([#&#8203;10993](axios/axios#10993))
- [@&#8203;bartlomieju](https://github.com/bartlomieju) ([#&#8203;11023](axios/axios#11023))
- [@&#8203;JSap0914](https://github.com/JSap0914) ([#&#8203;11019](axios/axios#11019))

[Full Changelog](axios/axios@v1.18.0...v1.18.1)

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yMTcuMSIsInVwZGF0ZWRJblZlciI6IjQzLjIxNy4xIiwidGFyZ2V0QnJhbmNoIjoiZXZvbHV0aW9ucy1wb3N0LTEuMS44IiwibGFiZWxzIjpbXX0=-->

Co-authored-by: leuwen-lc <[email protected]>
Reviewed-on: https://codeberg.org/leuwen-lc/rhdemo/pulls/178
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commit::fix The PR is related to a bugfix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AxiosError circular reference when stringifying since v1.12.0

2 participants