Vitest "Cannot access before initialization" - vi.mock Fix
Vitest hoists vi.mock calls to the top of the file, above your imports and variable declarations. A mock factory that references an outer variable then runs before that variable exists, throwing a reference error.
What this error means
A test using vi.mock('./api', () => ({ ... })) fails with "Cannot access 'mockFn' before initialization" or a Vitest message about resolving the mock. The variable looks defined above - but hoisting moved the mock call above it.
ReferenceError: Cannot access 'mockedFetch' before initialization
❯ src/user.test.ts:3:18
1| import { vi } from 'vitest';
2| const mockedFetch = vi.fn();
3| vi.mock('./api', () => ({ fetchUser: mockedFetch }));Diagnose it: flake, environment, or genuine failure?
Before debugging the assertion, establish whether the test is deterministic. A test that fails only in CI is usually order-dependent, time-dependent, or racing something, and fixing the assertion will not help.
# does it fail in isolation?
npx vitest run path/to/file.test.ts
# is it order dependent? run the suite in a random order twice
npx vitest run --sequence.shuffle
# is it a race? run the same file repeatedly
for i in $(seq 1 20); do npx vitest run path/to/file.test.ts || break; doneCommon causes
Mock factory references a non-hoisted variable
vi.mock is hoisted above imports and const/let declarations. A factory that closes over a normal variable runs before that variable is initialized, so it throws.
Relying on import order that hoisting changes
Because the mock is hoisted, the real module may already be imported elsewhere before the mock is registered, leaving the mock partially applied.
How to fix it
Declare mocks with vi.hoisted
vi.hoisted runs before the hoisted vi.mock, so variables it returns are safe to reference inside the factory.
import { vi } from 'vitest';
const { mockedFetch } = vi.hoisted(() => ({ mockedFetch: vi.fn() }));
vi.mock('./api', () => ({ fetchUser: mockedFetch }));Keep the factory self-contained
- Define
vi.fn()instances inside the factory, or viavi.hoisted, not as outerconsts. - Use
await import(...)aftervi.mockif you need the mocked module instance. - Avoid referencing test-scope variables the hoist would skip past.
CI-only causes worth ruling out
- Runners have fewer cores than a laptop, so timing-sensitive tests that pass locally fail under contention.
- No TTY and a different locale or timezone. Snapshot tests containing formatted dates or numbers are the usual casualty; pin
TZandLANGin the job. - Parallel workers sharing a database, a port, or a temp directory. Give each worker its own namespace.
- Default timeouts calibrated on a fast machine. A cold runner is slower on first execution, especially before any cache warms.
How to prevent it
- Use
vi.hoistedfor any value a mock factory needs to reference. - Keep mock factories free of outer-scope variable references.
- Remember
vi.mockruns first regardless of where you wrote it.