Troubleshooting cache errors
Find the symptom, not the tool. Most cache failures are one of four things: a URL with a path appended, a token with the wrong scope, a task that was never cacheable, or environment variables that did not reach the process that needed them.
What the status codes mean
- 401 Unauthorized
- The token is missing, invalid, revoked, or scoped to a different workspace. Generate a new one under your workspace's tokens. A
401is always about the credential - it never means the artifact is absent. - 403 Forbidden on upload
- Your token is read-only. Downloads work and uploads are rejected. That is the intended configuration for pull-request and fork builds; use a read-write token for the builds that should populate the cache, typically your protected branches. See tokens and access control.
- 404 Not Found
- Usually just a miss: no artifact exists for that task hash yet, so the build runs the task and (with a read-write token) populates the cache for next time. A 100% 404 rate is different - that is the appended-path mistake below.
- 409 Conflict
- Something tried to overwrite an existing cache key. Managed artifacts are immutable by design, so this is the API refusing to let a known good build be silently replaced. It is safe to ignore in a race between two runners producing the same hash.
Nothing ever hits the cache
- Every request 404s (Nx)
NX_SELF_HOSTED_REMOTE_CACHE_SERVERmust be the bare host (https://remote.cachely.dev) with no trailing path. Nx appends/v1/cache/<hash>itself, so adding it yourself doubles the path and nothing is ever found. The same rule applies to Gradle'surland Bazel's--remote_cache.- Requests succeed but always miss
- Different machines are computing different task hashes. The usual cause is an Nx version mismatch between CI runners and developers - hashes are not comparable across versions, so the cache is technically working and structurally useless. Pin the version. If the versions match, the inputs are drifting instead: the hit-rate guide covers over-keyed inputs, timestamps in outputs, and environment values leaking into the hash.
- The task is not cacheable
- Nx and Lerna only consult the cache for targets declared cacheable in
nx.json("cache": true). Gradle requiresorg.gradle.caching=trueand a task type that supports output caching. - The variables never reached the build
- Environment variables set on one CI step are invisible to the next. Declare them at the workflow or job level. Locally, confirm the shell that runs the build actually exports them - a variable set in a different terminal tab is the most common version of this.
Tool-specific symptoms
- Lerna runs but never hits the remote cache
- Confirm the task has
"cache": trueinnx.json, that both Nx environment variables are visible to thelernaprocess, and that every runner resolves the same Nx version. Lerna delegates cache reads and writes to Nx, so every Nx cause applies unchanged. - Gradle loads but never stores
- Loads working while stores are skipped means
isPushis false, or the token is read-only. Both are the intended CI-push / developer-read configuration - check whether the build you are looking at is meant to be a writer. A401in--infooutput means the token is wrong or revoked instead. - Gradle never stores or loads anything
- Confirm the URL is
https://remote.cachely.devwith no path,org.gradle.caching=trueis set (or--build-cacheis passed), the task is cacheable, andGRADLE_CACHE_TOKENis exported in the environment Gradle runs in. Run with--infoand look forFROM-CACHE. - Bazel never hits the cache
- Confirm
--remote_cacheis the bare host with no path - Bazel appends/ac/and/cas/itself. Check the--remote_headertoken is present and not revoked. Remember the committed.bazelrcin the Bazel setup disables uploads by default, so a workspace where only developers build will stay empty until trusted CI runs with--config=cachely-ci.
The dashboard shows no activity
Either no cache requests have arrived in the selected time range, or the token used belongs to a different workspace than the one you are viewing. Widen the range first - it is the cheaper check. If a full CI pipeline produced nothing at all, the variables did not reach the build; see CI setup.
Still stuck
Ask in the Cachely Discord - someone has usually hit the same status code - or email hello@cachely.dev with the build tool and version, the status code you are seeing, and whether the token is read-only or read-write. Either way, do not post or send cache artifacts or build logs containing your source paths - we do not need them and do not want them, and Discord is a public channel.