vitest-dev/vitest · error · Error

Cannot take a screenshot outside of a test.

Error message

Cannot take a screenshot outside of a test.

What it means

page.screenshot() reads getWorkerState().current and throws if there is no active test. Screenshots must be bound to a test task so Vitest can attribute the image, track repeat counts, and write it to the right path; calling it from module top-level, setup hooks that run outside a test context (rare), or after the test has finished yields no current task.

Source

Thrown at packages/browser/src/client/tester/context.ts:315

      iframeId: id,
    } satisfies IframeViewportEvent)
    return new Promise((resolve, reject) => {
      channel.addEventListener('message', function handler(e) {
        if (e.data.event === 'viewport:done' && e.data.iframeId === id) {
          channel.removeEventListener('message', handler)
          resolve()
        }
        if (e.data.event === 'viewport:fail' && e.data.iframeId === id) {
          channel.removeEventListener('message', handler)
          reject(new Error(e.data.error))
        }
      })
    })
  },
  async screenshot(options = {}) {
    const currentTest = getWorkerState().current
    if (!currentTest) {
      throw new Error('Cannot take a screenshot outside of a test.')
    }

    if (currentTest.concurrent) {
      throw new Error(
        'Cannot take a screenshot in a concurrent test because '
        + 'concurrent tests run at the same time in the same iframe and affect each other\'s environment. '
        + 'Use a non-concurrent test to take a screenshot.',
      )
    }

    const repeatCount = currentTest.result?.repeatCount ?? 0
    const taskName = getTaskFullName(currentTest)
    const number = screenshotIds[repeatCount]?.[taskName] ?? 1

    screenshotIds[repeatCount] ??= {}
    screenshotIds[repeatCount][taskName] = number + 1

    const name

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Move the page.screenshot() call inside an it() / test() body.
  2. If it's in a detached async callback, await the callback within the test so it resolves before the test ends.
  3. For setup-time captures, take the screenshot inside the first test or use beforeEach.

Example fix

// before — top-level call, no active test
await page.screenshot()
it('loads home', () => { ... })
// after
it('loads home', async () => {
  await page.screenshot()
})
Defensive patterns

Strategy: validation

Validate before calling

import { getWorkerState } from 'vitest'
const current = getWorkerState().current
if (current) {
  await page.screenshot()
} else {
  // not inside a test; skip or move the call
}

Prevention

When it happens

Trigger: Calling page.screenshot() at the top level of a test file, inside a beforeAll/beforeEach in certain non-test scopes, or in an async callback that resolves after the test has completed (detached promise). Defined at packages/browser/src/client/tester/context.ts:312-316.

Common situations: Taking a baseline screenshot at module load, calling page.screenshot() inside a setTimeout/setInterval callback that outlives the test, or invoking it from a utility invoked outside it()/test().

Related errors


AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03). Data as JSON: /data/errors/c141002116b3d322.json. Report an issue: GitHub.