jdx/mise · error · eyre::Report
not a directory: {}
Error message
not a directory: {} What it means
build_layer_from_dir requires src_dir to exist and be a directory; the guard fails fast before walking entries. Layers built from directories (tool installs, dotfile dirs) call this with the on-disk install root, so the error means the expected directory is missing or is not a directory.
Source
Thrown at src/oci/layer.rs:100
return Err(format!("{name} must not be empty"));
}
value
.parse::<u32>()
.map_err(|_| format!("{name} must be a non-negative integer <= {}", u32::MAX))
}
/// Build a reproducible gzipped tar layer from files in `src_dir`, placing them
/// under `target_prefix` inside the tar (e.g. `/mise/installs/node/20.0.0`).
///
/// `src_dir` must exist and be a directory. Symlinks are preserved; their
/// targets are NOT followed. `owner` is applied to every emitted tar entry.
pub fn build_layer_from_dir(
src_dir: &Path,
target_prefix: &str,
owner: LayerOwner,
) -> Result<LayerBlob> {
if !src_dir.is_dir() {
eyre::bail!("not a directory: {}", src_dir.display());
}
let entries = collect_sorted_entries(src_dir, false, owner)?;
build_layer_from_entries(&entries, target_prefix, owner)
}
/// Build a reproducible layer from one host file, symlink, or directory.
/// Directory contents are placed under `image_path`; a file or symlink is
/// placed at `image_path` itself.
pub fn build_layer_from_path(
host_path: &Path,
image_path: &str,
owner: LayerOwner,
) -> Result<LayerBlob> {
let metadata = std::fs::symlink_metadata(host_path)
.wrap_err_with(|| format!("reading metadata for {}", host_path.display()))?;
let target = image_path.trim_matches('/');
View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Run `mise install` (or `mise use -f`) so every tool version referenced exists under the installs directory, then rebuild.
- Verify the source path with `ls -ld <path>`; fix the config or create the directory.
- If the source is intentionally a single file, point the entry at the file with an exact destination file name instead of expecting directory semantics.
Example fix
# before mise oci build # tools never installed # after mise install && mise oci build
Defensive patterns
Strategy: validation
Validate before calling
import os, sys
for d in required_source_dirs:
if not os.path.isdir(d):
sys.exit(f"missing source directory: {d}; run `mise install` first") Type guard
fn is_usable_source_dir(p: &Path) -> bool {
p.is_dir() // symlink to dir also true; files/fifos/missing are false
} Prevention
- Run `mise install` before `mise oci build` in fresh environments (CI: cache or explicit install step).
- Pin the exact tool versions in mise.toml so installs are reproducible before layering.
- Check `ls -ld` on configured source paths when adding new copy/dotfile entries.
When it happens
Trigger: A [copy]/layer source path pointing at a regular file or a nonexistent path where a directory is required; a tool's install directory missing because the tool was never installed before `mise oci build` (the OCI builder consumes already-installed versions).
Common situations: Running mise oci build on a clean machine without `mise install` first; a typo'd or moved source path in config; a symlink-to-file passed where the caller expects a directory.
Related errors
- {}: does not look like an OCI image layout (missing index.js
- {}: does not look like an OCI image layout (missing index.js
- cannot copy a file or symlink to the image root
- copy image path {image_path:?} ends with `/` but {} is not a
- unsupported host path type: {}
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/317c01ca4d771544.
Report an issue: GitHub.