jdx/mise · error
base image has layers in its manifest but diff_ids in its…
Error message
base image {ref_} has {} layers in its manifest but {} diff_ids in its config — refusing to emit an OCI-spec-violating image What it means
When building on top of a base image, the builder cross-checks the number of layers in the base image's manifest against the number of diff_ids in its config blob. The OCI spec requires a 1:1 correspondence between manifest layers and config rootfs.diff_ids. If they diverge, mise refuses to emit an image that would violate the spec (and likely fail to pull/run).
Solutions
- Clear the cached base image (remove the cached OCI blobs/index for ref_) and pull it again from the registry.
- Verify the base image is well-formed, e.g. `skopeo inspect docker://<ref_>` or `crane manifest <ref_>`, and compare layer/diff_id counts.
- Pin the base image to a known-good digest (`ref@sha256:...`) to avoid a registry serving inconsistent data.
- If a mirror/proxy is in play, bypass it or fix it so manifest and config blobs come from the same source.
Example fix
// before let base = "registry.example.com/base:latest"; // after — pin a verified digest let base = "registry.example.com/base@sha256:abc123...";
Defensive patterns
Strategy: try-catch
Validate before calling
// before building, verify base image integrity with an external tool // crane manifest <ref> | jq '.layers | length' // crane config <ref> | jq '.rootfs.diff_ids | length' # must be equal
Try / catch
match builder.send() {
Err(e) if e.to_string().contains("diff_ids") => {
// purge cached base image and retry the pull
purge_base_cache();
retry_build();
}
r => r?,
} Prevention
- Pin base images by digest instead of mutable tags.
- Avoid untrusted mirror/proxy registries for base images.
- Re-pull the base image after any interrupted network operation.
- Verify base images with skopeo/crane in CI before building.
When it happens
Trigger: build (via send) with a base image whose registry manifest lists N layers but whose config blob's rootfs.diff_ids contains M != N entries — typically from a truncated/corrupted pull, a registry serving mismatched manifest/config blobs, or a hand-edited/cached image index.
Common situations: Proxy or mirror registries serving inconsistent blobs; corrupted local OCI cache after an interrupted download; base images produced by non-compliant tooling; manifest lists resolved to an incompatible platform's config.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- base image has layers in its manifest but diff_ids in its…
- blob digest mismatch: got
- cached OCI layer diff ID mismatch
- cached OCI layer digest mismatch
- cached OCI layer size mismatch
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/e7fe5d178501c400.
Report an issue: GitHub.
Appendix: source
Thrown at src/oci/builder.rs:271
.get("rootfs")
.and_then(|r| r.get("diff_ids"))
.and_then(|d| d.as_array())
.ok_or_else(|| {
eyre::eyre!(
"pulled base image {ref_} has no rootfs.diff_ids in its config \
— cannot produce a valid OCI image on top of it"
)
})?;
base_diff_ids = diff_ids_raw
.iter()
.map(|v| {
v.as_str().map(String::from).ok_or_else(|| {
eyre::eyre!("base image {ref_} has a non-string entry in rootfs.diff_ids")
})
})
.collect::<Result<Vec<_>>>()?;
if base_diff_ids.len() != base_layers.len() {
bail!(
"base image {ref_} has {} layers in its manifest but {} diff_ids in its \
config — refusing to emit an OCI-spec-violating image",
base_layers.len(),
base_diff_ids.len()
);
}
platform = pull.platform;
base_config_json = Some(pull.config_json);
}
// --- 2. Decide layer reuse and validate tool installs ---
// A tool layer is reused from the remote cache image when tool,
// version, in-image prefix, and file owner all match — in that case
// the layer is never built locally and the tool doesn't need to be
// installed at all.
let owner_str = format!("{}:{}", owner.uid, owner.gid);
let python_relocations: Vec<PythonRelocation> = versions
.iter()View on GitHub (pinned to 533346cc37)