vercel/turborepo · warning

Remote cache is read-only, skipping upload

Error message

Remote cache is read-only, skipping upload

What it means

In CacheMultiplexer::put (crates/turborepo-cache/src/multiplexer.rs:147-169), when a remote cache is configured but remote.write is false, the HTTP upload is skipped. To avoid spamming one warning per task, a should_print_skipping_remote_put flag prints the notice exactly once per run; cache reads from remote may still happen.

Source

Thrown at crates/turborepo-cache/src/multiplexer.rs:158

        if self.cache_config.local.write {
            self.fs
                .as_ref()
                .map(|fs| fs.put(anchor, key, files, duration))
                .transpose()?;
        }

        let http_result = match self.get_http_cache() {
            Some(http) => {
                if self.cache_config.remote.write {
                    let http_result = http.put(anchor, key, files, duration).await;

                    Some(http_result)
                } else {
                    if self
                        .should_print_skipping_remote_put
                        .load(Ordering::Relaxed)
                    {
                        turborepo_log::warn(
                            turborepo_log::Source::turbo(turborepo_log::Subsystem::Cache),
                            "Remote cache is read-only, skipping upload",
                        )
                        .emit();
                        self.should_print_skipping_remote_put
                            .store(false, Ordering::Relaxed);
                    }
                    // Cache is functional but running in read-only mode, so we don't want to try to
                    // write to it
                    None
                }
            }
            _ => None,
        };

        match http_result {
            Some(Err(CacheError::ApiClientError(
                box turborepo_api_client::Error::CacheDisabled { .. },

View on GitHub (pinned to f9245100cf)

Solutions

  1. If writes are intended, remove --remote-cache-read-only from the command/config so uploads resume.
  2. If read-only is intentional (consuming a shared cache), ignore the informational warning — it prints once per run.
  3. Check turbo.json cache/remoteCache settings and env vars for a lingering read-only option in CI templates.
  4. Verify directionality: ensure the producer pipeline writes with the flag off and only consumers run read-only.

Example fix

# before: producer also runs read-only, so it never uploads
turbo run build --remote-cache-read-only

# after: producer uploads, consumers stay read-only
# producer:
turbo run build
# consumer:
turbo run build --remote-cache-read-only
Defensive patterns

Strategy: validation

Validate before calling

#!/usr/bin/env bash
# producer jobs must not run read-only
if [[ "$PRODUCER" == "true" && "$*" == *--remote-cache-read-only* ]]; then
  echo "producer pipeline must upload — remove --remote-cache-read-only" >&2
  exit 1
fi
turbo run build "$@"

Prevention

When it happens

Trigger: Running with --remote-cache-read-only (or the corresponding turbo.json cache configuration / TURBO_CACHE_* env) while signed into a remote cache. Every put() with an http cache configured and cache_config.remote.write == false hits this branch once.

Common situations: Read-only caches are intentional for sharing a golden cache with dependents (e.g. a parent repo consuming a child repo's artifacts, or CI jobs that must not overwrite promoted artifacts), or someone left the flag on globally in CI scripts and wonders why hit rates never improve from their builds.

Related errors


AI-assisted analysis of vercel/turborepo@f9245100cf (2026-08-17). Data as JSON: /api/errors/0323258f082ff748. Report an issue: GitHub.