jdx/mise · error

podman pull failed: {}: {stderr}

Error message

podman pull failed: {}: {stderr}

What it means

To run an image, mise loads the built OCI layout into podman via `podman pull --quiet oci:<image_dir>` and treats a non-zero exit as failure, embedding the engine's exit status and full stderr in the error. The root cause is always in podman's output: corrupted/partial layout, unsupported layout features, storage/permission problems.

Source

Thrown at src/cli/oci/run.rs:275

/// Load the OCI layout at `image_dir` into the given engine and return the
/// image reference that should be passed to the engine's `run` subcommand.
///
/// We don't rely on `podman tag` here because `podman tag` takes an image
/// name/ID (not a transport reference), and the image name that `podman
/// pull oci:<dir>` assigns depends on the layout's `ref.name` annotation
/// and the podman version. Capturing the image ID printed by
/// `podman pull --quiet` is deterministic across versions.
fn load_image(engine: Engine, image_dir: &Path) -> Result<String> {
    match engine {
        Engine::Podman => {
            let src = format!("oci:{}", image_dir.display());
            let out = Command::new("podman")
                .args(["pull", "--quiet", &src])
                .output()
                .wrap_err("running `podman pull`")?;
            if !out.status.success() {
                let stderr = String::from_utf8_lossy(&out.stderr);
                bail!("podman pull failed: {}: {stderr}", out.status);
            }
            // `podman pull --quiet` prints just the image ID on stdout.
            let id = String::from_utf8(out.stdout)
                .wrap_err("podman pull produced non-utf8 output")?
                .trim()
                .to_string();
            if id.is_empty() {
                bail!("podman pull succeeded but printed no image ID");
            }
            Ok(id)
        }
        Engine::Docker => {
            // Stream the layout into `docker load` as a docker-archive. Pick
            // a per-invocation tag so concurrent `mise oci run` calls don't
            // clobber each other — a shared `mise-oci:run` tag would
            // otherwise race: the second load would overwrite the first
            // image before the first container started.
            let tag = format!(

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Read the embedded stderr — it names the actual podman failure
  2. Drop --image-dir to force a fresh build into a clean temp dir and retry
  3. Reclaim/repair engine storage: `podman system prune` (or `podman system reset` as last resort)
  4. Upgrade podman if the stderr mentions unsupported manifest/media types; or fall back to `--engine docker`

Example fix

# before
mise oci run --image-dir ./stale-layout -- bash
# after
mise oci run -- bash   # rebuilds layout fresh, avoiding corrupted blobs
Defensive patterns

Strategy: try-catch

Validate before calling

# optional pre-flight: if skopeo is available, validate the layout parses
skopeo inspect "oci:$IMAGE_DIR" >/dev/null 2>&1 || { echo "layout unreadable" >&2; exit 2; }

Try / catch

# bash: on pull failure, rebuild the layout once and retry
if ! mise oci run --image-dir "$dir" -- bash; then
  echo "pull failed; rebuilding layout" >&2
  mise oci build -o "$dir" || exit 1
  mise oci run --image-dir "$dir" -- bash || exit 1
fi

Prevention

When it happens

Trigger: A previous build was interrupted leaving truncated blobs in --image-dir; podman's storage is full or its DB is corrupted; a very old podman that cannot read the layout's manifest; the layout directory is not readable by the current user.

Common situations: Reusing a stale --image-dir across mise versions; rootless podman with a full ~/.local/share/containers; CI caching half-written layout directories; SELinux denying access to the layout path.

Related errors


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