{"record":{"id":"06458709e0ef78d0","repo":"jdx/mise","slug":"base-image-ref-has-base-layers-len-layers-in","errorCode":null,"errorMessage":"base image {ref_} has {base_layers.len} layers in its manifest but {base_diff_ids.len} diff_ids in its config — refusing to emit an OCI-spec-violating image","messagePattern":"base image (.+?) has (.+?) layers in its manifest but (.+?) diff_ids in its config — refusing to emit an OCI-spec-violating image","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/oci/builder.rs","lineNumber":261,"sourceCode":"                .get(\"rootfs\")\n                .and_then(|r| r.get(\"diff_ids\"))\n                .and_then(|d| d.as_array())\n                .ok_or_else(|| {\n                    eyre::eyre!(\n                        \"pulled base image {ref_} has no rootfs.diff_ids in its config \\\n                         — cannot produce a valid OCI image on top of it\"\n                    )\n                })?;\n            base_diff_ids = diff_ids_raw\n                .iter()\n                .map(|v| {\n                    v.as_str().map(String::from).ok_or_else(|| {\n                        eyre::eyre!(\"base image {ref_} has a non-string entry in rootfs.diff_ids\")\n                    })\n                })\n                .collect::<Result<Vec<_>>>()?;\n            if base_diff_ids.len() != base_layers.len() {\n                bail!(\n                    \"base image {ref_} has {} layers in its manifest but {} diff_ids in its \\\n                     config — refusing to emit an OCI-spec-violating image\",\n                    base_layers.len(),\n                    base_diff_ids.len()\n                );\n            }\n            platform = pull.platform;\n            base_config_json = Some(pull.config_json);\n        }\n\n        // --- 2. Decide layer reuse and validate tool installs ---\n        // A tool layer is reused from the remote cache image when tool,\n        // version, in-image prefix, and file owner all match — in that case\n        // the layer is never built locally and the tool doesn't need to be\n        // installed at all.\n        let owner_str = format!(\"{}:{}\", owner.uid, owner.gid);\n        let python_relocations: Vec<PythonRelocation> = versions\n            .iter()","sourceCodeStart":243,"sourceCodeEnd":279,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/oci/builder.rs#L243-L279","documentation":"When reusing a base image, mise cross-checks the manifest's layer list against the config's `rootfs.diff_ids` array; the OCI spec requires one diff_id per layer. If the counts diverge, the downloaded base image is malformed or mismatched (or the two documents came from different images), and mise refuses to build a spec-violating image on top of it.","triggerScenarios":"Pulling a base image whose manifest and config disagree on layer count — e.g. a corrupted/mutated registry cache, a proxy or mirror serving mismatched blobs, or fetching the manifest of one tag and the config of another.","commonSituations":"Corporate registry mirrors rewriting manifests; interrupted/corrupted local image caches; manually constructing or trimming image layers; registry bugs after force-pushing a tag with different content.","solutions":["Re-pull the base image (clear any cache/mirror) so manifest and config come from the same digest-pinned source: `docker pull <ref>@sha256:<digest>` and pin the digest in config.","Verify the registry/mirror isn't rewriting content; bypass the mirror and pull from the upstream registry.","Check for tooling that edited the image config (custom `docker commit`/save-load round trips) and regenerate the base image.","Report the mismatch to the registry operator if a specific tag consistently returns inconsistent manifest/config."],"exampleFix":"// before (mutable tag through a flaky mirror)\nlet base = \"mirror.internal/mybase:latest\";\n// after (digest-pinned, consistent manifest+config)\nlet base = \"mirror.internal/mybase@sha256:abc123...\";","handlingStrategy":"validation","validationCode":"// before building, verify layer/diff_id consistency of the base image\nconst ok = baseManifest.layers.length === baseConfig.rootfs.diff_ids.length;\nif (!ok) throw new Error('base image manifest/config layer count mismatch — re-pull');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pin base images by digest (`ref@sha256:...`) so manifest and config always come from the same content.","Avoid flaky mirrors/proxies that can serve mismatched blobs.","Re-pull the base image if it was force-pushed or mutated.","Validate the pulled image with a tool (e.g. `cosign`/schema checks) before using it as a base."],"tags":["oci","image-spec","integrity","layers"],"backgroundTag":"checksum-mismatch","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}