Skip to content
Latchkey LogoLatchkey home

The Cypress binary is missing in CI

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.

Runner log: Cypress reporting a missing binary, then cypress install putting it in that folder
The recorded run: the install wrote 819M of binary to one cache folder, the test step read another, and cypress install finished the job in the folder that was empty.
Diagram of the npm package, the global binary cache and the four ways the two paths diverge
Two things install in two places. Every version of this failure is the second place going missing, and every fix is a way of making the two agree.

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

Reproduced on a Latchkey runner

Run 2026-09-20·Runner latchkey-small·Exit code 0

install step  CYPRESS_CACHE_FOLDER=/home/runner/cypress-cache-install
cypress package 16.1.0, install cache holds version 16.1.0 at 819M
test step     CYPRESS_CACHE_FOLDER=/home/runner/cypress-cache-run
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

Properly caching the binary will fix this error and avoid downloading and unzipping Cypress.

Alternatively, you can run 'cypress install' to download the binary again.

https://on.cypress.io/not-installed-ci-error

----------

Platform: linux-x64 (Ubuntu - 24.04.4 LTS)
Cypress Version: 16.1.0
cypress verify exited 1, now running the fix its own message names
[COMPLETED] [10:26:25]  Finished Installation   /home/runner/cypress-cache-run/16.1.0

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.

PlatformDefault binary cacheWhat to cache in CI
Linux~/.cache/CypressThat folder, keyed on the Cypress version
macOS~/Library/Caches/CypressSame, and note the runner user differs from a laptop
Windows/AppData/Local/Cypress/CacheSame, with the path style of the runner
Any, overriddenWhatever CYPRESS_CACHE_FOLDER saysThe same value in every job that touches Cypress

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

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 for the line a managed runner draws between a failure it can act on and a misconfiguration it should hand back to you.

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.

Frequently asked questions

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.

Related guides

References

Cache the binary folder, not node_modules. Latchkey's cache action takes your existing path and key as they are. Start free → 30-day trial · No credit card