jdx/mise · error · eyre::Report

{}: index.json lists {} manifests; multi-manifest layouts ar

Error message

{}: index.json lists {} manifests; multi-manifest layouts are not supported

What it means

Same layout reader as the empty-index case, but here index.json lists more than one manifest. mise only supports pushing single-manifest layouts (one platform); a multi-manifest index — such as a multi-platform bundle from `docker buildx --output type=oci`, ORAS, or hand-merged layouts — is rejected because push cannot decide which manifest represents the image.

Source

Thrown at src/oci/registry.rs:932

    update_index: bool,
) -> Result<PushSummary> {
    eyre::ensure!(
        !crate::config::Settings::get().offline(),
        "offline mode is enabled"
    );
    let r = Reference::parse(reference)?;
    let layout = ImageLayout {
        root: image_dir.to_path_buf(),
    };

    // Resolve the layout's single manifest. `mise oci build` always writes
    // exactly one manifest into index.json.
    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!("{}: index.json lists no manifests", image_dir.display()),
        many => bail!(
            "{}: index.json lists {} manifests; multi-manifest layouts are not supported",
            image_dir.display(),
            many.len()
        ),
    };
    let manifest_bytes = layout.read_blob(&manifest_desc.digest)?;
    let manifest: ImageManifest =
        serde_json::from_slice(&manifest_bytes).wrap_err("parsing image manifest blob")?;

    // Cross-repo mount source: the base image's repository, when it lives on
    // the destination registry (and isn't the destination repo itself).
    let mount_from = manifest
        .annotations
        .get(ANNOTATION_BASE_NAME)
        .and_then(|name| Reference::parse(name).ok())
        .filter(|base| base.registry == r.registry && base.repository != r.repository)
        .map(|base| base.repository);

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Push the layout produced by `mise oci build` for a single platform — do not point mise at buildx/ORAS multi-platform exports
  2. Build one platform at a time so each layout keeps exactly one manifest
  3. Use `crane push`/`oras push` for hand-assembled or multi-manifest layouts; use mise oci push for mise-built layouts
Defensive patterns

Strategy: validation

Validate before calling

// Reject multi-manifest layouts before push (same guard, count > 1).
fn layout_manifest_count(image_dir: &Path) -> usize {
    std::fs::read(image_dir.join("index.json"))
        .ok()
        .and_then(|b| serde_json::from_slice::<serde_json::Value>(&b).ok())
        .and_then(|v| v["manifests"].as_array().map(|a| a.len()))
        .unwrap_or(0)
}

if layout_manifest_count(&image_dir) != 1 {
    anyhow::bail!("push needs a single-manifest mise-built layout");
}

Type guard

fn is_single_manifest_layout(image_dir: &Path) -> bool {
    layout_manifest_count(image_dir) == 1
}

Prevention

When it happens

Trigger: Pushing a layout directory produced by external multi-platform tooling, or one mutated by appending manifests to index.json, instead of the layout written by `mise oci build`.

Common situations: Teams mixing docker buildx OCI exports with mise oci build outputs in one artifacts dir; hand-assembling multi-arch indexes then trying to push via mise.

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/cca9a8dbb3efd71b. Report an issue: GitHub.