{"record":{"id":"bf888854ced8cc1e","repo":"jdx/mise","slug":"expected-exactly-one-manifest-in-index-json","errorCode":null,"errorMessage":"{}: expected exactly one manifest in index.json","messagePattern":"(.+?): expected exactly one manifest in index\\.json","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/oci/docker_archive.rs","lineNumber":46,"sourceCode":"    #[serde(rename = \"Config\")]\n    config: String,\n    #[serde(rename = \"RepoTags\")]\n    repo_tags: Vec<String>,\n    #[serde(rename = \"Layers\")]\n    layers: Vec<String>,\n}\n\n/// Stream the OCI layout at `image_dir` into `docker load`, tagging the\n/// loaded image as `tag`.\npub(crate) fn load_into_docker(image_dir: &Path, tag: &str) -> Result<()> {\n    let layout = ImageLayout {\n        root: image_dir.to_path_buf(),\n    };\n    let index_bytes = crate::file::read(image_dir.join(\"index.json\"))?;\n    let index: ImageIndex = serde_json::from_slice(&index_bytes).wrap_err(\"parsing index.json\")?;\n    let manifest_desc = match index.manifests.as_slice() {\n        [one] => one,\n        _ => bail!(\n            \"{}: expected exactly one manifest in index.json\",\n            image_dir.display()\n        ),\n    };\n    let manifest_bytes = layout.read_blob(&manifest_desc.digest)?;\n    let manifest: ImageManifest =\n        serde_json::from_slice(&manifest_bytes).wrap_err(\"parsing image manifest blob\")?;\n    let config_bytes = layout.read_blob(&manifest.config.digest)?;\n\n    // Validate every layer digest before it's used as a path component in\n    // `write_docker_archive` (which reads via `blob_path`, bypassing the\n    // check `read_blob` performs) — a crafted `--image-dir` layout could\n    // otherwise escape the blobs directory with `sha256:../…`.\n    for layer in &manifest.layers {\n        crate::oci::layout::validate_sha256_digest(&layer.digest)?;\n    }\n\n    let mut command = Command::new(\"docker\");","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/oci/docker_archive.rs#L28-L64","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"let index: serde_json::Value =\n    serde_json::from_slice(&std::fs::read(layout.join(\"index.json\"))?)?;\nlet n = index[\"manifests\"].as_array().map(|a| a.len()).unwrap_or(0);\nassert_eq!(n, 1, \"index.json must contain exactly one manifest, got {n}\");","typeGuard":null,"tryCatchPattern":"match load_into_docker(dir) {\n    Err(e) if e.to_string().contains(\"expected exactly one manifest\") => {\n        // rebuild layout or pick a single manifest before retrying\n    }\n    r => r?,\n}","preventionTips":["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."],"tags":["oci","docker","image-index","validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}