Describe the bug
Spying on Set.prototype.add causes infinite recursion in Vitest 5.0.1 when the method is called:
import { expect, it, vi } from 'vitest'
it('can spy on Set.prototype.add', () => {
const spy = vi.spyOn(Set.prototype, 'add')
try {
new Set([1])
expect(spy).toHaveBeenCalledWith(1)
} finally {
spy.mockRestore()
}
})
Expected: the test passes and the spy records the call, as it does on Vitest 4.1.10 and 4.1.11.
Actual: the test fails with RangeError: Maximum call stack size exceeded. The stack repeatedly enters Set.add in @vitest/spy/dist/index.js.
This also reproduces with @vitest/spy alone in plain Node, without the Vitest runner or Vite. Each mock invocation in 5.0.1's spy implementation calls DIRTY_MOCK_STATES.add(...), which calls the spied method again. This bookkeeping was added in #11092.
Reproduction
Minimal reproduction repository
git clone https://github.com/why-reproductions-are-required/vitest-set-add-spy-recursion.git
cd vitest-set-add-spy-recursion
npm ci
npm test
For the smaller Node-only reproduction:
Both commands exit with code 1 and a stack overflow on 5.0.1, which was the latest stable release when checked on 2026-09-17. Both pass on 4.1.10 and 4.1.11. The README contains the comparison commands. Vite remains pinned to 8.3.0 in all cases.
System Info
System:
OS: macOS 26.2
CPU: (16) arm64 Apple M4 Max
Binaries:
Node: 24.21.0
npm: 11.19.0
npmPackages:
@vitest/spy: 5.0.1
vite: 8.3.0
vitest: 5.0.1
Used Package Manager
npm
Validations
Codex assisted with preparing and running the reproduction and drafting this report.
Describe the bug
Spying on
Set.prototype.addcauses infinite recursion in Vitest5.0.1when the method is called:Expected: the test passes and the spy records the call, as it does on Vitest
4.1.10and4.1.11.Actual: the test fails with
RangeError: Maximum call stack size exceeded. The stack repeatedly entersSet.addin@vitest/spy/dist/index.js.This also reproduces with
@vitest/spyalone in plain Node, without the Vitest runner or Vite. Each mock invocation in 5.0.1's spy implementation callsDIRTY_MOCK_STATES.add(...), which calls the spied method again. This bookkeeping was added in #11092.Reproduction
Minimal reproduction repository
For the smaller Node-only reproduction:
Both commands exit with code 1 and a stack overflow on
5.0.1, which was the latest stable release when checked on 2026-09-17. Both pass on4.1.10and4.1.11. The README contains the comparison commands. Vite remains pinned to8.3.0in all cases.System Info
Used Package Manager
npm
Validations
Codex assisted with preparing and running the reproduction and drafting this report.