{"record":{"id":"cd0c05345272501c","repo":"jdx/mise","slug":"cache-from-must-reference-the-same-repository-as","errorCode":null,"errorMessage":"--cache-from must reference the same repository as the destination (got {}/{}, destination is {}/{})","messagePattern":"--cache-from must reference the same repository as the destination \\(got (.+?)/(.+?), destination is (.+?)/(.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cli/oci/push.rs","lineNumber":173,"sourceCode":"\n    /// Fetch the layer-reuse cache image: `--cache-from` if given, otherwise\n    /// the destination ref itself (the previously pushed image under this\n    /// tag). Returns `None` with `--no-cache`, when no previous image exists,\n    /// or when the lookup fails — a broken cache must never fail the push.\n    async fn fetch_layer_cache(&self) -> Result<Option<registry::RemoteImage>> {\n        if self.no_cache {\n            return Ok(None);\n        }\n        let cache_ref = self.cache_from.as_deref().unwrap_or(&self.reference);\n        if let Some(cache_from) = &self.cache_from {\n            // Reused layer blobs are never uploaded — they must already live\n            // in the destination repository, so a cache image from a\n            // different repo would produce a manifest referencing blobs the\n            // destination doesn't have.\n            let dest = registry::Reference::parse(&self.reference)?;\n            let cache = registry::Reference::parse(cache_from)?;\n            if dest.registry != cache.registry || dest.repository != cache.repository {\n                bail!(\n                    \"--cache-from must reference the same repository as the destination \\\n                     (got {}/{}, destination is {}/{})\",\n                    cache.registry,\n                    cache.repository,\n                    dest.registry,\n                    dest.repository\n                );\n            }\n        }\n        match registry::fetch_remote_image(cache_ref).await {\n            Ok(remote) => {\n                if remote.is_none() {\n                    debug!(\"no previous image at {cache_ref} — building all layers locally\");\n                }\n                Ok(remote)\n            }\n            Err(e) => {\n                warn!(\"could not fetch layer cache from {cache_ref}: {e} — building all layers\");","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/cli/oci/push.rs#L155-L191","documentation":"`--cache-from` names an already-pushed image whose layers push reuses (skipping re-upload). Because reused layer blobs are never uploaded, they must already live in the destination repository; a cache image from a different registry or repository would produce a manifest referencing blobs the destination does not have. mise therefore requires cache and destination to match on registry AND repository (tag may differ).","triggerScenarios":"`mise oci push --cache-from ghcr.io/other/repo:cache ghcr.io/you/devenv:tag`, or mixing registries (`ghcr.io/you/devenv` vs `docker.io/you/devenv`). Note: when --cache-from is omitted, the destination itself is used as the cache ref, so this only fires with an explicit mismatched flag.","commonSituations":"Promoting images between namespaces or registries while keeping the old cache ref; CI copying a cache ref from another project's workflow; renaming the destination repo but not the cache variable.","solutions":["Drop `--cache-from` entirely — push then defaults to using the destination ref as its own cache","Point --cache-from at another tag in the SAME repo: `--cache-from ghcr.io/you/devenv:cache`","If you need cross-repo caching, first `mise oci push` (or `skopeo copy`) the cache image into the destination repository"],"exampleFix":"# before\nmise oci push --cache-from ghcr.io/other/devenv:cache ghcr.io/you/devenv:tag\n# after\nmise oci push --cache-from ghcr.io/you/devenv:cache ghcr.io/you/devenv:tag","handlingStrategy":"validation","validationCode":"# bash: cache ref must share registry/repo with destination\ndest=\"ghcr.io/you/devenv:tag\"\ncache=\"${CACHE_FROM:-$dest}\"\ndest_rr=\"${dest%:*}\"; cache_rr=\"${cache%:*}\"\nif [ \"$dest_rr\" != \"$cache_rr\" ]; then\n  cache=\"$dest_rr:cache\"   # fall back to same-repo cache tag\nfi\nmise oci push --cache-from \"$cache\" \"$dest\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Derive --cache-from from the destination string (same repo, ':cache' tag) instead of a separate variable","When promoting across registries, explicitly push the cache image into the destination repo first"],"tags":["oci","push","cache","registry","argument-validation"],"backgroundTag":"registry-repository-mismatch","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}