{"record":{"id":"a152566601211a1f","repo":"jdx/mise","slug":"source-is-required-for-the-home-directory-itself","errorCode":null,"errorMessage":"source is required for the home directory itself","messagePattern":"source is required for the home directory itself","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/files.rs","lineNumber":977,"sourceCode":"            FileMode::Symlink\n        }\n    }\n}\n\npub(crate) fn dotfiles_root() -> PathBuf {\n    file::replace_path(&Settings::get().dotfiles.root)\n}\n\npub(crate) fn implied_source(target: &Path) -> Result<PathBuf> {\n    let home: &Path = &dirs::HOME;\n    let rel = target.strip_prefix(home).map_err(|_| {\n        eyre::eyre!(\n            \"source is required for targets outside $HOME: {}\",\n            target.display_user()\n        )\n    })?;\n    if rel.as_os_str().is_empty() {\n        bail!(\"source is required for the home directory itself\");\n    }\n    Ok(dotfiles_root().join(rel))\n}\n\npub(crate) fn source_is_implied(req: &FileRequest) -> bool {\n    if req.mode == FileMode::Content {\n        return false;\n    }\n    match implied_source(&req.target) {\n        Ok(source) => source == req.source,\n        Err(_) => false,\n    }\n}\n\npub(crate) fn resolve_target_arg(target: &str) -> PathBuf {\n    lexical_normalize(&file::replace_path(target))\n}\n","sourceCodeStart":959,"sourceCodeEnd":995,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/files.rs#L959-L995","documentation":"When a non-track dotfile declares no `source` and no `content`, mise infers the source path from the target's path relative to $HOME (target `~/.gitconfig` implies source `<dotfiles_root>/gitconfig`). This inference cannot work for the home directory itself: the relative path is empty, so `implied_source` fails with this message.","triggerScenarios":"Declaring `[dotfiles.\"~\"]` (or an equivalent absolute $HOME path) with no `source`/`content`, reached via `validate_incoming_files`, `merge_file_entry`, or `source_is_implied` during dotfile expansion.","commonSituations":"Trying to manage $HOME wholesale as a single entry, a glob/template expanding to `~` itself, or a mistyped target like `~` instead of `~/.something`.","solutions":["Target a concrete file or subdirectory (e.g. `~/.gitconfig`) so the source can be inferred.","Add an explicit `source` key if you genuinely need a special target.","Remove the entry if it was accidental (e.g. a wildcard or templating artifact resolving to `~`)."],"exampleFix":"// before\n[dotfiles.\"~\"]\n\n// after\n[dotfiles.\"~/.gitconfig\"]","handlingStrategy":"validation","validationCode":"function assertNonHomeTarget(target) {\n  const t = target.replace(/^~\\/?/, '');\n  if (t === '' ) throw new Error('source is required for the home directory itself; target a concrete file or subdir');\n}","typeGuard":null,"tryCatchPattern":"try {\n  applyDotfiles();\n} catch (e) {\n  if (/source is required for the home directory itself/.test(e.message)) {\n    console.error('Replace the ~ target with a concrete file or subdirectory entry');\n  } else throw e;\n}","preventionTips":["Never declare `~` itself as a dotfile target","Check template/glob output so dynamic targets can never collapse to `~`","Rely on implied source only for targets with at least one path segment under $HOME"],"tags":["dotfiles","source-inference","home-directory","mise"],"backgroundTag":"missing-required-config-field","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"}