jdx/mise · error
: expected exactly one manifest in index.json
Error message
{}: expected exactly one manifest in index.json What it means
When loading an OCI image layout into docker, the library parses the layout's `index.json` and expects it to contain exactly one manifest descriptor. An index with zero or multiple manifests is ambiguous — the loader would not know which image to stream to `docker load` — so it fails with the image directory path in the message.
Solutions
- Regenerate the image layout so index.json contains a single manifest (rebuild the image with `mise oci build`).
- If the layout is multi-manifest, pick/extract the single desired manifest into its own layout directory before loading.
- Validate index.json contents (manifests array length == 1) before calling the loader.
Defensive patterns
Strategy: validation
Validate before calling
let index: serde_json::Value =
serde_json::from_slice(&std::fs::read(layout.join("index.json"))?)?;
let n = index["manifests"].as_array().map(|a| a.len()).unwrap_or(0);
assert_eq!(n, 1, "index.json must contain exactly one manifest, got {n}"); Try / catch
match load_into_docker(dir) {
Err(e) if e.to_string().contains("expected exactly one manifest") => {
// rebuild layout or pick a single manifest before retrying
}
r => r?,
} Prevention
- Use a fresh output directory per image build; never append builds to one layout.
- Don't hand-edit index.json; regenerate it with `mise oci build`.
- For multi-arch needs, build one layout per platform.
When it happens
Trigger: Calling `load_into_docker` on an image directory whose `index.json` has an empty `manifests` array or more than one entry (e.g. a multi-arch index or an index accumulated from several builds).
Common situations: Pointing the loader at a registry-style layout exported with `docker save` of a multi-platform image; reusing an OCI layout directory that was appended to by multiple builds; a corrupted or hand-edited index.json.
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
- : expected exactly one manifest in index.json
- `auth` for is not `user:password
- get failed for
- cannot copy a file or symlink to the image root
- copy image path ends with `/` but is not a directory…
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/bf888854ced8cc1e.
Report an issue: GitHub.
Appendix: source
Thrown at src/oci/docker_archive.rs:46
#[serde(rename = "Config")]
config: String,
#[serde(rename = "RepoTags")]
repo_tags: Vec<String>,
#[serde(rename = "Layers")]
layers: Vec<String>,
}
/// Stream the OCI layout at `image_dir` into `docker load`, tagging the
/// loaded image as `tag`.
pub(crate) fn load_into_docker(image_dir: &Path, tag: &str) -> Result<()> {
let layout = ImageLayout {
root: image_dir.to_path_buf(),
};
let index_bytes = crate::file::read(image_dir.join("index.json"))?;
let index: ImageIndex = serde_json::from_slice(&index_bytes).wrap_err("parsing index.json")?;
let manifest_desc = match index.manifests.as_slice() {
[one] => one,
_ => bail!(
"{}: expected exactly one manifest in index.json",
image_dir.display()
),
};
let manifest_bytes = layout.read_blob(&manifest_desc.digest)?;
let manifest: ImageManifest =
serde_json::from_slice(&manifest_bytes).wrap_err("parsing image manifest blob")?;
let config_bytes = layout.read_blob(&manifest.config.digest)?;
// Validate every layer digest before it's used as a path component in
// `write_docker_archive` (which reads via `blob_path`, bypassing the
// check `read_blob` performs) — a crafted `--image-dir` layout could
// otherwise escape the blobs directory with `sha256:../…`.
for layer in &manifest.layers {
crate::oci::layout::validate_sha256_digest(&layer.digest)?;
}
let mut command = Command::new("docker");View on GitHub (pinned to 533346cc37)