{"record":{"id":"18976e93b325af8b","repo":"jdx/mise","slug":"not-a-directory-cache","errorCode":null,"errorMessage":"not a directory: {}","messagePattern":"not a directory: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/oci/layer/cache.rs","lineNumber":25,"sourceCode":"\nuse super::*;\n\n#[derive(Serialize, Deserialize)]\nstruct CachedLayer {\n    digest: String,\n    diff_id: String,\n    size: u64,\n}\n\npub(crate) fn build_cached_tool_layer(\n    src_dir: &Path,\n    target_prefix: &str,\n    owner: LayerOwner,\n    relocation: &ToolRelocation,\n    cache_dir: &Path,\n) -> Result<(LayerBlob, bool)> {\n    if !src_dir.is_dir() {\n        eyre::bail!(\"not a directory: {}\", src_dir.display());\n    }\n    let entries = collect_sorted_entries(src_dir, false, owner, Some(relocation))?;\n    let key = fingerprint(&entries, target_prefix, owner, relocation)?;\n    let record_path = cache_dir.join(format!(\"{key}.json\"));\n    let _lock = match crate::lock_file::LockFile::new(&record_path).lock() {\n        Ok(lock) => lock,\n        Err(err) => {\n            debug!(\"could not lock OCI tool layer cache: {err:#}\");\n            return Ok((\n                build_layer_from_entries(&entries, target_prefix, owner, Some(relocation))?,\n                false,\n            ));\n        }\n    };\n    match read_cached_layer(&record_path, cache_dir) {\n        Ok(Some(blob)) => return Ok((blob, true)),\n        Ok(None) => {}\n        Err(err) => debug!(\"ignoring invalid OCI tool layer cache: {err:#}\"),","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/oci/layer/cache.rs#L7-L43","documentation":"`build_cached_tool_layer` fingerprints a tool directory and reuses a cached layer blob when possible. Before anything else it requires the source directory to exist; a missing or non-directory path fails with `not a directory: <path>`. The cache itself also rebuilds records when blobs or diff_ids are corrupt.","triggerScenarios":"Calling `build_cached_tool_layer` with a tool install directory that is absent or a file — e.g. the cached-build path resolved from an install dir deleted between resolution and layer packaging.","commonSituations":"Concurrent builds racing with a `mise uninstall`/cache clean; wrong cache_dir or install prefix; first build after switching MISE_DATA_DIR where nothing is installed yet.","solutions":["Ensure the tool is installed and `src_dir.is_dir()` before invoking the cached layer build.","Reinstall the tool (`mise install <tool>@<version>`) to recreate the directory.","Fix path resolution (install prefix / cache_dir) if it points at the wrong location; note corrupt cache blobs are rebuilt automatically, but the source dir must still exist."],"exampleFix":"// before\nlet (blob, cached) = build_cached_tool_layer(&install_dir, \"opt\", owner, &reloc, &cache_dir)?;\n\n// after\nif !install_dir.is_dir() {\n    bail!(\"tool install dir missing: {} — run `mise install` first\", install_dir.display());\n}\nlet (blob, cached) = build_cached_tool_layer(&install_dir, \"opt\", owner, &reloc, &cache_dir)?;","handlingStrategy":"validation","validationCode":"if !install_dir.is_dir() {\n    bail!(\"install dir {} missing; run `mise install {}@{}` first\", install_dir.display(), tool, version);\n}","typeGuard":null,"tryCatchPattern":"match build_cached_tool_layer(&install_dir, prefix, owner, &reloc, &cache_dir) {\n    Err(e) if e.to_string().starts_with(\"not a directory:\") => {\n        bail!(\"tool dir {} vanished; reinstall and avoid concurrent uninstalls\", install_dir.display())\n    }\n    r => r,\n}","preventionTips":["Install tools before invoking cached layer builds.","Avoid concurrent uninstall/clean operations during parallel image builds.","Derive install_dir and cache_dir from the same mise config to prevent mismatches."],"tags":["oci","layer","cache","filesystem"],"backgroundTag":"path-is-not-a-directory","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"}