Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

An EPERM from Cypress is not one single bug. First read the complete error and identify the operation (mkdir, image write, unlink, or rename) and the exact path. Then check the operating system, Cypress version, process account, and the configuration loaded by that run. A creation/write failure needs a writable destination; an unlink or cleanup failure concerns an old screenshot tree and may involve Cypress’s pre-run asset deletion.

Cypress stores manual screenshots and failure screenshots below screenshotsFolder, whose documented default is cypress/screenshots (configuration reference). The sections below give a safe way to change that folder, distinguish cleanup errors from capture errors, and verify where files actually land.

1. Capture the evidence before changing settings

Do not start by repeatedly changing the folder. Save the entire EPERM line, including the verb and path, and note:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Operating system and whether the run is local, containerized, or CI.
  • Cypress version and the command used (cypress open versus cypress run).
  • The configured screenshotsFolder value and the configuration file that was loaded.
  • The spec being run and whether the path contains nested directories, spaces, a network share, or a synchronized folder.
  • Whether the named operation is creating a directory, writing an image, deleting an existing asset, or renaming a temporary file.

These distinctions matter. Setting a different destination cannot repair an EPERM while deleting the previous destination, and disabling cleanup cannot make a protected destination writable.

2. Configure a writable screenshot destination

Cypress 10 and later

Set screenshotsFolder in the configuration used to start the run. A project-relative directory is usually easiest to reason about:

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  screenshotsFolder: 'artifacts/cypress-screenshots',
  e2e: {
    baseUrl: 'http://localhost:3000'
  }
})

Use the equivalent TypeScript or ECMAScript-module syntax if your project does. The important point is that the setting belongs in the loaded Cypress configuration, not in an individual test. Confirm the value in the same environment and command that produces the error.

Older Cypress configuration

Projects using the older JSON configuration can set the same key in cypress.json:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
{
  "screenshotsFolder": "artifacts/cypress-screenshots"
}

Do not assume a path is writable merely because your interactive shell can write there. Cypress may run as a different account in a service, container, or CI job. Check the parent directory’s permissions as that account and ensure the parent can be created.

How Cypress builds paths beneath the root

screenshotsFolder is a root, not necessarily the final image directory. Cypress derives subdirectories from the spec path, and cy.screenshot() also supports nested paths in the screenshot name (screenshot command documentation). For example:

cy.screenshot('checkout/payment/declined')

can require artifacts/cypress-screenshots/checkout/payment to be created before the image is written. A permission check on only the root can therefore miss a denied or read-only nested directory.

3. Separate capture failures from pre-run cleanup failures

When the error names mkdir, write, or a temporary rename

Inspect every component of the destination. Remove read-only or protected locations, avoid placing the folder inside a system directory, and test with a short project-relative path. If CI uses a service account, grant that account access or choose a workspace directory it owns. Also check free space and whether an antivirus, backup, or synchronization process is holding newly created files.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When the error names unlink or an old screenshot

During cypress run, Cypress clears the contents of screenshotsFolder by default because trashAssetsBeforeRuns defaults to true (screenshots and videos guide). Cleanup can include nested directories, not just image files. If the named path is an old asset, inspect which process owns or locks it and whether the Cypress account can delete it.

You can opt out of automatic deletion:

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  screenshotsFolder: 'artifacts/cypress-screenshots',
  trashAssetsBeforeRuns: false
})

This preserves existing files and makes cleanup your responsibility; it does not change the destination and does not fix permissions. Keep only disposable artifacts in a folder that Cypress manages, or implement an explicit cleanup step with the correct account.

Windows-specific lock investigation

A Cypress issue reports an intermittent Windows 11 case in which deletion of nested screenshot folders failed; in that reporter’s reproduction, stopping the development process allowed deletion (issue #29404). Treat this as a scenario to test, not a universal diagnosis. Stop Cypress, the application dev server, file watchers, Explorer previews, and other tools that may hold handles, then retry. If the failure disappears, identify which process was locking the tree before re-enabling services one at a time.

4. Verify the path Cypress actually uses

Do not infer the final path from the configured root alone. Cypress 10 changed generated screenshot path derivation to strip common ancestor paths shared by specs. An issue discussion also reports that output paths can differ according to which specs run (issue #22159). Consequently, run one known spec and inspect the produced tree, then run the relevant spec set and compare it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Delete or move unrelated files from a disposable test folder.
  2. Run one spec that calls cy.screenshot('path-check').
  3. Record the complete path and whether Cypress created spec-derived directories.
  4. Run the same command in CI and compare the resolved workspace and account.
  5. Use the observed path when diagnosing permissions or locks; do not rely on a path copied from a different Cypress version.

If you are changing the setting dynamically, be cautious. A Cypress configuration issue discussion describes changing screenshotsFolder with Cypress.config() inside a test without changing the actual output location (issue #6407). Configure the folder before the run through the project configuration and verify the result instead.

5. A repeatable troubleshooting decision tree

What the error names Most useful check Appropriate fix
mkdir or directory creation Can the Cypress process create every parent and nested directory? Choose a writable project/workspace path and correct account permissions.
Image write or temporary rename Is the destination writable, present, and free of locks or storage exhaustion? Change the path or permissions; stop locking processes and check disk space.
unlink, remove, or old asset Is trashAssetsBeforeRuns clearing a tree that another process owns? Release locks, fix ownership, or set trashAssetsBeforeRuns: false and manage cleanup.
Path differs between runs Did Cypress version or selected spec set change? Inspect the actual tree and account for common-ancestor/spec-derived paths.

6. Common fixes that do not solve the underlying EPERM

  • Changing only the root string: this cannot fix a locked file in the old root when startup cleanup fails.
  • Turning off cleanup for a write error: trashAssetsBeforeRuns: false affects deletion only; it does not grant write permission.
  • Changing configuration inside a test: runtime mutation may not alter the output location for the run.
  • Giving a broad “run as administrator” workaround: it can hide an account or ownership problem and is unsuitable for CI. Prefer a workspace and permissions that match the Cypress process.
  • Putting unrelated documents in the screenshot folder: a future run may delete them when cleanup is enabled.

7. Reliability and CI practices

Use an isolated artifact directory

Keep screenshots under the job workspace, separate from source files and persistent user data. Create the directory in the job’s setup phase using the same user that runs Cypress. Publish it as a CI artifact after the run rather than placing it on a shared network location.

Make cleanup intentional

For ephemeral CI workspaces, the default cleanup is convenient. For debugging or retaining history, disable it and give each run a unique artifact directory, or clean that directory in a controlled pre-step. Never assume a cleanup setting is a permissions fix.

Control concurrency

Two jobs should not share the same screenshot tree if either can delete or overwrite files. Use per-job paths or isolated workspaces. If a local watcher and Cypress run concurrently, stop or reconfigure the watcher when testing a lock-related failure.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Record diagnostic context

Log Cypress and Node versions, the resolved workspace, selected specs, effective screenshot setting, and the full EPERM path. This turns an intermittent CI report into a comparison between successful and failing processes without exposing credentials.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

8. Or skip the browser setup

If your goal is a clean image or PDF of a URL rather than Cypress-specific test artifacts, ScreenshotNeo provides a single HTTP request. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response reports the result with X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

See the complete parameter list and authentication details in the ScreenshotNeo documentation. A minimal cURL call is:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

The same request in Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

And in Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo also supports full-page lazy-image capture, CSS-selector element capture, device presets or custom viewports, dark mode, retina scale, PDF paper and page-range controls, custom CSS and JavaScript, clicks and waits, request/resource blocking, headers, cookies, user agents, authorization, timezone and geolocation, transparent backgrounds, resizing, configurable-TTL caching, signed image links, async jobs with signed webhooks, bulk capture for 100 URLs per call, a usage API, and an OpenAPI specification. Existing integrations can use the parameter names common to other screenshot APIs.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Every plan includes every feature: 1,000 screenshots per month are free with no card; paid plans start at $5 for 3,000 shots, with yearly billing giving two months free. Create a free ScreenshotNeo account to try the 1,000-shot allowance.

9. FAQ

Can I keep Cypress’s default folder and still avoid EPERM?

Yes, if the default cypress/screenshots is writable and no process locks its contents. The setting itself is not required to change; verify the failing operation first.

Why does the same spec produce a different-looking directory in another run?

Spec-derived paths and Cypress version behavior can change the subdirectories beneath the root. Compare the actual tree, version, and selected spec set rather than comparing only the root setting.

Should I delete the screenshot folder manually?

Only when you have confirmed it contains disposable artifacts and you are using the same account that runs Cypress. If another process owns files, stop or reconfigure that process first; otherwise the next run can fail again.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Can I keep Cypress’s default folder and still avoid EPERM?

Yes, provided the default cypress/screenshots directory is writable and no process locks its contents. Verify the failing operation before changing the setting.

Why does the same spec produce a different-looking directory in another run?

Spec-derived paths and Cypress version behavior can change subdirectories beneath the configured root. Compare the actual tree, version, and selected spec set.

Should I delete the screenshot folder manually?

Only after confirming it contains disposable artifacts and using the same account as Cypress. Release any process locks first.

The Bottom Line

EPERM is a symptom, not a diagnosis: identify the operation and exact path, configure a writable destination, treat cleanup separately, and verify the path generated by your Cypress version and spec set.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.