# The Cypress binary is missing in CI

> The Cypress binary is missing in GitHub Actions when the folder the install wrote to and the folder the test job reads are not the same path.

Source: https://latchkey.dev/learn/failures/cypress-binary-missing-in-ci  
Updated: 2026-09-20

When a CI job reports that the Cypress binary is missing, it is not a download failure: the npm package installed correctly, and the binary is either sitting somewhere else on the same disk or was never carried between two jobs. Cypress keeps the binary in a global cache outside `node_modules`, so restoring `node_modules` without that cache produces this message every time.

## What this error means

The message names a path, and the path is the whole diagnosis. Cypress prints where it expected the binary, then lists the two reasons it knows about: caching node_modules without caching the binary folder, and installing in an earlier step whose filesystem did not survive. Below that it offers the fix in one line, `cypress install`. There is a second wording for the same condition. Cypress chooses its message from its own CI detection, so a laptop gets "No version of Cypress is installed in" for the identical situation, which is why this sentence turns up in bug reports about CI and almost never in ones about local runs. The run below is the failure with nothing substituted: the real package from the real registry, the real binary really downloaded, and one environment variable different between the step that installs and the step that runs. The binary is on disk the whole time, under the other folder, and the log prints its size just before the failure.

```Actions log, test step
The cypress npm package is installed, but the Cypress binary is missing.

We expected the binary to be installed here: /home/runner/cypress-cache-run/16.1.0/Cypress/Cypress

Reasons it may be missing:

- You're caching 'node_modules' but are not caching this path: /home/runner/cypress-cache-run
- You ran 'npm install' at an earlier build step but did not persist: /home/runner/cypress-cache-run
```

## Common causes

### node_modules was cached and the binary folder was not

The reason Cypress lists first in its own error, and the most common one in practice. A cache key built from the lockfile restores the package, the postinstall step never runs because npm sees nothing to do, and the download that would have fetched the binary is skipped along with it. The package and the binary are two artifacts, and only one of them came back.

### The install job and the test job disagree about the cache folder

Either because `CYPRESS_CACHE_FOLDER` is set in one and not the other, or because they resolve different homes. A step with `container:` has a different `HOME` from the runner user, so the same default expands to a different absolute path, and a cache restored outside the container is not where the container looks.

### The binary was never downloaded, by design

Base images are often built with `CYPRESS_INSTALL_BINARY=0` to keep them small, which Cypress documents as skipping the download entirely. That is a reasonable choice, and it means something later has to supply the binary. When that step is missing, or is a cache restore that misses, this message is the result.

### The install ran as a different user than the run

An install under `sudo`, or in a container as root, writes the cache into that user's home. The test step runs as the ordinary runner user, resolves its own home, and finds nothing. The message looks identical to the caching cause and is fixed differently, so it is worth printing the resolved path in both steps before guessing.

## How to fix it

### Cache the binary folder, not node_modules

1. Set `CYPRESS_CACHE_FOLDER` to a path inside the workspace so every step, container or not, resolves the same absolute path.
2. Key the cache on the Cypress version, because the folder holds one directory per version and a stale key wastes the restore.
3. Cache your package manager's store separately, and let the install run on every job.

```.github/workflows/ci.yml
env:
  CYPRESS_CACHE_FOLDER: ${{ github.workspace }}/.cypress-cache

steps:
  - uses: actions/cache@v6
    with:
      path: ${{ github.workspace }}/.cypress-cache
      key: cypress-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
  - run: npm ci
  - run: npx cypress run
```

### Run the command the error names

When the package is present and the binary is not, `cypress install` downloads and unzips it into the folder the current environment resolves. It is safe to run unconditionally: with the binary already in place it is close to a no-op, and it removes a class of cache misses from your pipeline in one line.

```Terminal
npx cypress install
npx cypress cache list --size
```

### Print the path from both steps before changing anything

The fastest way to tell the four causes apart is to make both steps say where they are looking. If the two lines differ, it is a path problem. If they match and the folder is empty, the download never happened or the cache restore missed.

```.github/workflows/ci.yml
- run: |
    echo "HOME=$HOME"
    echo "cache=${CYPRESS_CACHE_FOLDER:-$HOME/.cache/Cypress}"
    ls -la "${CYPRESS_CACHE_FOLDER:-$HOME/.cache/Cypress}" || true
```

### Keep the binary in the image if you build one

For a container job, install the binary in the image and set the cache folder to the location you installed it into, so the container is self-sufficient and no cache restore is on the critical path. If you deliberately build with the download skipped, add the install to the entrypoint instead of hoping a cache covers it.

```Dockerfile
ENV CYPRESS_CACHE_FOLDER=/opt/cypress-cache
RUN npm ci && npx cypress install && npx cypress cache list
```

## How to prevent it

- Set `CYPRESS_CACHE_FOLDER` to an absolute workspace path in one place, at workflow level.
- Cache that folder keyed on the Cypress version, and never cache `node_modules`.
- Run `npx cypress install` after the dependency install, so a cache miss costs a download rather than a red build.
- Print the resolved cache path in CI, so the next occurrence is diagnosed from the log rather than from guesses.

## Where Cypress actually puts the binary

The npm package is a small command line wrapper. The application it runs is a separate download, unzipped into a global cache that is shared by every project on the machine, which is what makes it survivable between runs and also what makes it easy to lose.

| Platform | Default binary cache | What to cache in CI |
| --- | --- | --- |
| Linux | `~/.cache/Cypress` | That folder, keyed on the Cypress version |
| macOS | `~/Library/Caches/Cypress` | Same, and note the runner user differs from a laptop |
| Windows | `/AppData/Local/Cypress/Cache` | Same, with the path style of the runner |
| Any, overridden | Whatever `CYPRESS_CACHE_FOLDER` says | The same value in every job that touches Cypress |

> Cypress documentation is blunt about the other half: "Do not cache `node_modules` across builds. Instead, cache the package manager's own cache directory." The install and the run each resolve one of these paths, and every version of this failure is those two answers differing: the variable set in one job and not the other, a container step whose `HOME` is not the runner's, a lockfile cache that restores the package without the binary, or an image built with the download skipped. The four causes below are those four, in the order they turn up.

## What the recorded run shows, and what no runner can do about it

The install wrote 819M into one folder and the test step looked in another, on the same machine, seconds apart. The step then ran the fix Cypress names in its own error text, and the binary landed in the folder that had been empty.

This is the failure class where a retry is worthless, and it is worth being explicit about that, because most of the pages in this cluster are about the opposite. A cache path that does not hold the binary does not hold it on the second attempt either. Nothing in the path is transient, the command is deterministic, and the only thing that changes the outcome is changing the configuration. [See how self-healing works](/documentation/self-healing) for the line a managed runner draws between a failure it can act on and a misconfiguration it should hand back to you.

## FAQ

### Why is the Cypress binary missing after npm ci?

Because `npm ci` only installs the package, and the binary comes from the postinstall step that downloads it into a global cache. If `node_modules` was restored from a cache, npm has nothing to install and the postinstall never runs, so the binary is never fetched. Cache the Cypress cache folder instead, and run `npx cypress install` after the dependency install.

### What should CYPRESS_CACHE_FOLDER be set to in GitHub Actions?

An absolute path inside the workspace, set once at workflow level so every job and every container step resolves the same value. The default is `~/.cache/Cypress` on Linux, which is fine until a container step brings its own home directory and quietly resolves somewhere else.

### Does cypress install download the binary again every run?

Only when it is not already in the resolved cache folder. With a restored cache the command finds the version it needs and does almost nothing, which is why running it unconditionally after the dependency install is cheap insurance. `npx cypress cache list --size` reports what is in the folder if you want the step to be visible in the log.

### Why does the error say the binary is missing when it is on disk?

Because it is on disk under a different path from the one this step resolves. The message prints the exact location it looked in, and comparing that with the folder the install step wrote to settles it in one line. The usual culprits are a cache folder set in one job and not another, or a container step whose home directory is not the runner's.

## References

- [Cypress documentation: continuous integration and caching the binary](https://docs.cypress.io/app/continuous-integration/overview)
- [Cypress documentation: advanced installation, cache folder and environment variables](https://docs.cypress.io/app/references/advanced-installation)
- [cypress-io/cypress#21022: the cypress npm package is installed, but the Cypress binary is missing](https://github.com/cypress-io/cypress/issues/21022)
- [cypress-io/github-action#1246: the same failure through the official action](https://github.com/cypress-io/github-action/issues/1246)

---

Latchkey runs CI/CD that repairs its own failures. Agent entry points: https://latchkey.dev/agent.txt, https://latchkey.dev/openapi.json, https://latchkey.dev/llms.txt
