{"record":{"id":"2a7155e3b493058e","repo":"jdx/mise","slug":"target-raw-target-must-be-absolute-or-start-wit-2a7155","errorCode":null,"errorMessage":"{target_raw}: target must be absolute or start with ~/","messagePattern":"(.+?): target must be absolute or start with ~/","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cli/dotfiles/track.rs","lineNumber":65,"sourceCode":"    yes: bool,\n}\n\nimpl DotfilesTrack {\n    pub(crate) async fn run(self) -> Result<()> {\n        let _declarations = declaration_lock()?;\n        let config = Config::get().await?;\n        let managed = crate::system::files::composed_files_from_config(&config)?;\n        let global = declaration_file(false)?;\n        let mut edits: BTreeMap<PathBuf, DeclarationEdit> = BTreeMap::new();\n        let mut locations = BTreeMap::new();\n        let mut declared: Vec<(String, PathBuf)> = vec![];\n        let mut manual = vec![];\n        for target_raw in &self.targets {\n            let target = crate::system::files::resolve_target_arg(target_raw)\n                .components()\n                .collect::<PathBuf>();\n            if target.is_relative() {\n                bail!(\"{target_raw}: target must be absolute or start with ~/\");\n            }\n            crate::system::history::tracked::ensure_portable_ancestors(&target)?;\n            let target_key = normalized_target(&target);\n            if !target.exists() && !target.is_symlink() {\n                warn!(\n                    \"dotfiles: {} does not exist yet; it is captured once it does\",\n                    target.display_user()\n                );\n            }\n            let existing = managed\n                .iter()\n                .find(|req| req.target == target && req.mode == FileMode::Track);\n            let config_path = if let Some(existing) = existing\n                && crate::config::is_global_config(&existing.origin.config)\n                && !crate::config::is_system_config(&existing.origin.config)\n            {\n                existing.origin.config.clone()\n            } else if managed","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/cli/dotfiles/track.rs#L47-L83","documentation":"`mise bootstrap dotfiles track <target>` requires each target to resolve to an absolute path (or a `~/`-prefixed path). `resolve_target_arg` normalizes the input; if the result is still relative, track refuses because tracked dotfiles must be addressed unambiguously across shells and checkpoint restores.","triggerScenarios":"Running `dotfiles track` with a bare relative path like `dotfiles/vimrc` or `./config` that neither starts with `/` nor `~/` and cannot be anchored.","commonSituations":"Typing a path relative to the current directory out of habit; scripting track calls with relative paths; copy-pasting paths from listings without expansion.","solutions":["Prefix the path with `~/` or use an absolute path: `mise bootstrap dotfiles track ~/dotfiles/vimrc`","Expand `$HOME` or `.` in scripts before calling track"],"exampleFix":"// before\nmise bootstrap dotfiles track dotfiles/vimrc\n// after\nmise bootstrap dotfiles track ~/dotfiles/vimrc","handlingStrategy":"validation","validationCode":"case \"$target\" in\n  /*|~/*) ;; # ok\n  *) target=\"$HOME/${target#./}\" ;;\nesac","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass absolute or ~/ paths to `dotfiles track`","Expand variables in scripts before invoking track","Normalize paths with realpath before tracking"],"tags":["cli","dotfiles","path","validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}