jdx/mise · error

--cache-from must reference the same repository as the…

Error message

--cache-from must reference the same repository as the destination (got {}/{}, destination is {}/{})

What it means

`mise oci push --cache-from` requires the cache image to live in the same registry/repository as the push destination. Cross-repository cache images would yield manifests referencing blobs the destination registry doesn't have, so mise rejects the mismatch by comparing parsed References with same_repository().

Solutions

  1. Change --cache-from to an image in the same registry/repository as the destination (e.g. an earlier tag)
  2. Update --reference to the same repository as the cache image
  3. Drop --cache-from and build without layer cache

Example fix

// before
mise oci push --cache-from ghcr.io/old/app:cache ghcr.io/new/app:tag
// after
mise oci push --cache-from ghcr.io/new/app:cache ghcr.io/new/app:tag
Defensive patterns

Strategy: validation

Validate before calling

[[ "$cache_from" == "$(dirname "$dest_ref")"* ]] || echo "cache-from must share the destination repository"

Prevention

When it happens

Trigger: Running a push (fetch_layer_cache called from BuildOptions) where the parsed --cache-from Reference has a different registry or repository than the --reference destination.

Common situations: Caching from a public mirror (docker.io/library/...) while pushing to ghcr.io, or moving the image to a new namespace but keeping the old --cache-from value.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/cd0c05345272501c. Report an issue: GitHub.

Appendix: source

Thrown at src/cli/oci/push.rs:177

    /// Fetch the layer-reuse cache image: `--cache-from` if given, otherwise
    /// the destination ref itself (the previously pushed image under this
    /// tag). Returns `None` with `--no-cache`, when no previous image exists,
    /// or when the lookup fails — a broken cache must never fail the push.
    async fn fetch_layer_cache(&self) -> Result<Option<registry::RemoteImage>> {
        if self.no_cache {
            return Ok(None);
        }
        let cache_ref = self.cache_from.as_deref().unwrap_or(&self.reference);
        if let Some(cache_from) = &self.cache_from {
            // Reused layer blobs are never uploaded — they must already live
            // in the destination repository, so a cache image from a
            // different repo would produce a manifest referencing blobs the
            // destination doesn't have.
            let dest = registry::Reference::parse(&self.reference)?;
            let cache = registry::Reference::parse(cache_from)?;
            if !dest.same_repository(&cache) {
                bail!(
                    "--cache-from must reference the same repository as the destination \
                     (got {}/{}, destination is {}/{})",
                    cache.registry,
                    cache.repository,
                    dest.registry,
                    dest.repository
                );
            }
        }
        match registry::fetch_remote_image(cache_ref).await {
            Ok(remote) => {
                if remote.is_none() {
                    debug!("no previous image at {cache_ref} — building all layers locally");
                }
                Ok(remote)
            }
            Err(e) => {
                warn!("could not fetch layer cache from {cache_ref}: {e} — building all layers");

View on GitHub (pinned to 533346cc37)