vitest-dev/vitest · error · Error

Cannot take a screenshot in a concurrent test because…

Error message

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.

What it means

Concurrent tests in Vitest browser mode share the same iframe, so a screenshot would capture an interleaved DOM from sibling tests. Vitest forbids screenshots in tests marked .concurrent to prevent misleading artifacts. The guard sits at the top of page.screenshot() right after the current-test check.

Solutions

  1. Remove .concurrent from the specific test that needs a screenshot (or its describe block).
  2. Keep concurrency for fast assertions but isolate the visual test by splitting it into a separate non-concurrent suite.
  3. Replace the screenshot with a DOM assertion (e.g. toMatchAriaSnapshot) which is safe under concurrency.

Example fix

// before
it.concurrent('shows chart', async () => { await page.screenshot() })
// after
it('shows chart', async () => { await page.screenshot() })
Defensive patterns

Strategy: validation

Validate before calling

import { getWorkerState } from 'vitest'
const t = getWorkerState().current
if (t?.concurrent) {
  // do not screenshot in concurrent tests
} else {
  await page.screenshot()
}

Type guard

function canScreenshot(): boolean {
  const t = getWorkerState().current
  return !!t && !t.concurrent
}

Prevention

When it happens

Trigger: Declaring a test as it.concurrent('...', ...) (or it.concurrent.only) and calling page.screenshot() inside it; enabling test.concurrent at the suite/describe level; importing a helper that screenshots while the suite is configured concurrent.

Common situations: Enabling concurrent mode globally to speed up the suite; copy-pasting a screenshot helper into a concurrent suite; running with --no-isolate or concurrent config defaults.

Related errors


AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11). Data as JSON: /api/errors/f0f19bf4746d388b. Report an issue: GitHub.

Appendix: source

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

        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
      = options.path || `${taskName.replace(/[^a-z0-9]/gi, '-')}-${number}.png`

    const [element, ...mask] = await Promise.all([
      options.element ? serializeElement(options.element, options) : undefined,

View on GitHub (pinned to 1fa9837ec2)