{"record":{"id":"ebaac092374524ad","repo":"jdx/mise","slug":"dotfiles-req-target-raw-mode-symlink-each-r","errorCode":null,"errorMessage":"[dotfiles].\"{req.target_raw}\": mode symlink-each requires a directory source: {req.source.display}","messagePattern":"\\[dotfiles\\]\\.\"(.+?)\": mode symlink-each requires a directory source: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/oci/builder.rs","lineNumber":950,"sourceCode":"                \"[dotfiles].\\\"{}\\\": source does not exist: {}\",\n                req.target_raw,\n                req.source.display()\n            );\n        }\n\n        match req.mode {\n            // a tracked file lives on the machine that tracks it; an image\n            // has nothing to copy\n            FileMode::Track => continue,\n            FileMode::Symlink | FileMode::Copy => {\n                collect_source_as_files(&req.source, &oci_target_path(req)?, &mut entries)\n                    .wrap_err_with(|| {\n                        format!(\"adding [dotfiles].\\\"{}\\\" to OCI image\", req.target_raw)\n                    })?;\n            }\n            FileMode::SymlinkEach => {\n                if !req.source.is_dir() {\n                    bail!(\n                        \"[dotfiles].\\\"{}\\\": mode symlink-each requires a directory source: {}\",\n                        req.target_raw,\n                        req.source.display()\n                    );\n                }\n                let target = oci_target_path(req)?;\n                entries.add_dir(target.clone())?;\n                for entry in walkdir::WalkDir::new(&req.source).sort_by_file_name() {\n                    let entry = entry?;\n                    let ft = entry.file_type();\n                    if !(ft.is_file() || ft.is_symlink()) {\n                        continue;\n                    }\n                    let rel = entry.path().strip_prefix(&req.source)?;\n                    let path = format!(\"{target}/{}\", rel.to_string_lossy().replace('\\\\', \"/\"));\n                    entries.add_file(\n                        path,\n                        file::read(entry.path())?,","sourceCodeStart":932,"sourceCodeEnd":968,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/oci/builder.rs#L932-L968","documentation":"The `symlink-each` dotfile mode creates one symlink per child entry of the source, so the source must be a directory. If the source is a regular file (or other non-directory), mise rejects the entry because per-entry symlinking is undefined for a single file.","triggerScenarios":"`[dotfiles].\"target\"` entry with `mode = \"symlink-each\"` whose `source` points at a file instead of a directory — commonly after changing a directory source into a single file, or a typo pointing at a sibling file.","commonSituations":"Pointing symlink-each at `~/.config/foo.conf` intending to symlink it; refactoring a dotfiles dir into individual files while keeping the old mode; a symlink-each source that is itself a symlink to a file.","solutions":["Change the mode to `symlink` or `copy` for single-file sources.","Point `source` at the directory whose children should each be symlinked.","Split the entry: use `symlink-each` for the directory and a separate `symlink`/`content` entry for individual files."],"exampleFix":"# before\n[dotfiles.\"/root/.config\"]\nsource = \"~/.gitconfig\"\nmode = \"symlink-each\"\n# after\n[dotfiles.\"/root/.gitconfig\"]\nsource = \"~/.gitconfig\"\nmode = \"symlink\"","handlingStrategy":"validation","validationCode":"if (req.mode === 'symlink-each' && !fs.statSync(req.source).isDirectory()) {\n  throw new Error(`symlink-each requires a directory source: ${req.source}`);\n}","typeGuard":"const isDir = (p) => { try { return fs.statSync(p).isDirectory(); } catch { return false; } };","tryCatchPattern":null,"preventionTips":["Reserve `symlink-each` for directories; use `symlink`/`copy` for single files.","When converting a dotfiles directory into individual files, update the mode accordingly.","Check sources with `test -d` in pre-build scripts."],"tags":["dotfiles","config","validation","symlink"],"backgroundTag":"path-is-not-a-directory","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}