Repository navigation
fix(core): make AxiosError cause non-enumerable to prevent circular JSON errors - #10913
jasonsaayman merged 5 commits into
Conversation
There was a problem hiding this comment.
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.
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.
|
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. |
…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.
4ba480a to
cafc3d6
Compare
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) |  |  | --- ### 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. ([#​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. ([#​10917](axios/axios#10917), [#​10930](axios/axios#10930), [#​10942](axios/axios#10942), [#​10993](axios/axios#10993)) - Runtime and Type Correctness: Fixed several runtime crashes, type definition mismatches, and incorrect error handling paths. ([#​10959](axios/axios#10959), [#​11021](axios/axios#11021)) - AxiosURLSearchParams: Switched the encoder callback to an arrow function so `encoder.call(this)` receives the `AxiosURLSearchParams` instance correctly. ([#​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 ([#​11007](axios/axios#11007), [#​11010](axios/axios#11010), [#​11023](axios/axios#11023), [#​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. ([#​11011](axios/axios#11011), [#​11012](axios/axios#11012), [#​11013](axios/axios#11013), [#​11014](axios/axios#11014), [#​11015](axios/axios#11015), [#​11016](axios/axios#11016), [#​11017](axios/axios#11017), [#​11026](axios/axios#11026)) #### 🌟 New Contributors We are thrilled to welcome our new contributors. Thank you for helping improve axios: - [@​webdevelopersrinu](https://github.com/webdevelopersrinu) ([#​10913](axios/axios#10913)) - [@​sijie-Z](https://github.com/sijie-Z) ([#​10993](axios/axios#10993)) - [@​bartlomieju](https://github.com/bartlomieju) ([#​11023](axios/axios#11023)) - [@​JSap0914](https://github.com/JSap0914) ([#​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
Summary
Since #6982,
AxiosError.from()setcauseas an enumerable own property. NativeErrorcause(per spec,new Error(msg, { cause })) is non-enumerable. Because the wrapped error routinely holds circular internals (sockets, requests, agents), an enumerablecausemakes structured loggers (pino/winston/bunyan) and any own-property walk throwConverting 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: definecauseas non-enumerable (matches nativeError; mirrors the existingmessagedescriptor incl.__proto__: null).lib/adapters/fetch.js: same fix on the fetch cancel-errorcausepath.tests/unit/core/AxiosError.test.js: regression tests — non-enumerable, still accessible, logger-style walk no longer throws,toJSON()output unchanged.causeremains fully accessible for debugging. Serialized output is unchanged (toJSON()already excludedcause). No public API change → no.d.tsupdates. No new deps. 78/78 focused unit tests + lint green locally.Checklist
Summary by cubic
Make
AxiosError.causenon-enumerable to match nativeErrorand prevent circular JSON errors in structured loggers. Applied inAxiosError.from(), and in fetch adapter cancel and network-error paths;causestays accessible andtoJSON()is unchanged.Description
Summary of changes
causeinAxiosError.from().causefor cancel and network errors (replaceObject.assignwithObject.defineProperty).Reasoning
Errorsemantics; fixes regression since v1.12.0.Additional context
Docs
Update
/docs/error handling guide to noteAxiosError.causeis non-enumerable and add a tip about logger/serialization behavior.Testing
AxiosError.from()sets non-enumerablecause, remains accessible, excluded fromtoJSON(), and safe for own-property serialization.causeis non-enumerable and safe for logger-style serialization.Semantic version impact
Patch: bug fix with no public API change.
Written for commit a7a5541. Summary will update on new commits.