jdx/mise · error

{}: does not look like an OCI image layout (missing index.js

Error message

{}: does not look like an OCI image layout (missing index.json)

What it means

When `--image-dir` is given, `mise oci push` treats the directory as a pre-existing OCI image layout to publish (it does NOT write the build output there — without the flag it builds into a temp dir). An OCI layout is identified by an `index.json` at its root; if that file is missing, mise refuses rather than guessing whether the dir is a partial or wrong-path layout.

Source

Thrown at src/cli/oci/push.rs:107

impl Push {
    pub async fn run(self) -> Result<()> {
        Settings::get().ensure_experimental("mise oci push")?;

        if !self.reference.contains('/') {
            bail!(
                "push destination must be a fully-qualified reference \
                 (e.g. `ghcr.io/you/devenv:tag`); got {:?}",
                self.reference
            );
        }
        // Keep the temp dir alive for the duration of the push — it removes
        // itself on drop, so multi-hundred-megabyte image layouts don't
        // accumulate in /tmp.
        let mut reused_layers = 0;
        let (image_dir, _tempdir_guard): (PathBuf, Option<TempDir>) =
            if let Some(d) = &self.image_dir {
                if !d.join("index.json").is_file() {
                    bail!(
                        "{}: does not look like an OCI image layout (missing index.json)",
                        d.display()
                    );
                }
                (d.clone(), None)
            } else {
                let td = TempDir::with_prefix("mise-oci-push-")
                    .wrap_err("creating temp dir for oci build output")?;
                let out_dir = td.path().join("image");
                let opts = BuildOptions {
                    out_dir: out_dir.clone(),
                    from: self.from.clone(),
                    tag: Some(self.reference.clone()),
                    mount_point: self.mount_point.clone(),
                    owner: self.owner,
                    include_mise: !self.no_mise,
                    copy: vec![],
                    reuse_from: self.fetch_layer_cache().await?,

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Build a proper layout first: `mise oci build -o ./image ...`, then `mise oci push --image-dir ./image ghcr.io/...`
  2. Verify the marker file exists: `ls ./out/index.json` — it must be a file at the root of --image-dir
  3. Point --image-dir at the directory that directly contains index.json (and oci-layout/), not its parent or a subdirectory

Example fix

# before
mise oci push --image-dir ./out ghcr.io/you/devenv:tag   # ./out is empty
# after
mise oci build -o ./out && mise oci push --image-dir ./out ghcr.io/you/devenv:tag
Defensive patterns

Strategy: validation

Validate before calling

# bash: guard before push
image_dir="${1:?image dir required}"
if [ ! -f "$image_dir/index.json" ]; then
  echo "$image_dir is not an OCI layout (no index.json); building..." >&2
  mise oci build -o "$image_dir" || exit 1
fi
mise oci push --image-dir "$image_dir" dest:tag

Prevention

When it happens

Trigger: `mise oci push --image-dir ./out ghcr.io/you/devenv:tag` where ./out has no index.json — e.g. an empty dir, the parent of the real layout, an interrupted build's leftovers, or a directory that only contains blobs/ but no index.json.

Common situations: Passing the directory you intended as build output instead of one produced by `mise oci build -o`; copying/extracting an artifact and dropping index.json; confusing the layout root with the surrounding project or temp dir.

Related errors


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