{"record":{"id":"6ffd3cbbc9c25082","repo":"jdx/mise","slug":"path-path-raw-must-be-absolute-or-start-with","errorCode":null,"errorMessage":"path \"{path_raw}\" must be absolute or start with ~/, ignoring entry","messagePattern":"path \"(.+?)\" must be absolute or start with ~/, ignoring entry","errorType":"validation","errorClass":"eyre::Report","httpStatus":null,"severity":"warning","filePath":"src/system/edits.rs","lineNumber":222,"sourceCode":"\nfn split_edit_key(path_and_id: &str) -> Option<(String, String)> {\n    let (path, id) = path_and_id.rsplit_once('/')?;\n    if path.is_empty() || path == \"~\" || path == \"/\" || id.is_empty() {\n        return None;\n    }\n    Some((path.to_string(), id.to_string()))\n}\n\nfn resolve_entry(\n    path_raw: &str,\n    id: String,\n    entry: EditTomlEntry,\n    base: &Path,\n    config_path: &Path,\n) -> Result<EditRequest> {\n    let path = file::replace_path(path_raw);\n    if path.is_relative() {\n        bail!(\"path \\\"{path_raw}\\\" must be absolute or start with ~/, ignoring entry\");\n    }\n    // ids end up inside marker lines — keep them to characters that can't\n    // collide with the marker syntax itself\n    if id.is_empty() || !id.chars().all(|c| c.is_alphanumeric() || \"_-.\".contains(c)) {\n        bail!(\n            \"\\\"{path_raw}\\\".{id:?}: ids may only contain letters, digits, '_', '-', and '.', ignoring entry\"\n        );\n    }\n    let entry = match entry {\n        EditTomlEntry::Block(inline) => EditTomlTable {\n            block: Some(inline),\n            source: None,\n            template: None,\n            line: None,\n            comment: None,\n        },\n        EditTomlEntry::Table(table) => table,\n    };","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/edits.rs#L204-L240","documentation":"In [dotfiles], edit-entry keys are \"<path>/<id>\" where the path (after ~ expansion) must be absolute. A relative path is rejected with this warning and the entry is skipped — edits target machine-specific files, so there is no meaningful base for a relative target. Whole-file [dotfiles] entries have their own resolution; this guard applies to block/line edits.","triggerScenarios":"A key like \".config/fish/config.fish/mise\" (no leading ~ or /), or \"$HOME/.zshrc/activate\" — $VAR is not expanded, so the path stays relative.","commonSituations":"Writing $HOME out of shell habit instead of ~; dropping the ~/ when converting a whole-file dotfiles entry to an edit; assuming paths resolve relative to the mise.toml that declared them (they deliberately do not).","solutions":["Prefix the path with ~/ (\"~/.zshrc/activate\") or use a full absolute path (\"/etc/hosts/dev\")","Replace $HOME-style variables with ~ — only ~ is expanded","Re-run `mise bootstrap dotfiles status` and confirm the entry now appears"],"exampleFix":"# before\n[dotfiles]\n\".config/fish/config.fish/mise\" = { line = 'eval (mise activate fish)' }\n\n# after\n[dotfiles]\n\"~/.config/fish/config.fish/mise\" = { line = 'eval (mise activate fish)' }","handlingStrategy":"validation","validationCode":"# every [dotfiles] edit key's path segment must start with / or ~/\ngrep -E '^\"?[^\" ]+' mise.toml | ... # or simpler:\n[[ \"$key\" == ~/* || \"$key\" == /* ]] || echo \"edit path must be absolute or ~/-prefixed: $key\" >&2","typeGuard":"fn is_valid_edit_path(path_raw: &str) -> bool {\n    let p = mise_path::replace(path_raw); // ~-expanded\n    p.is_absolute()\n}","tryCatchPattern":null,"preventionTips":["Always write edit targets as ~/.… or /…; $HOME is not expanded","After editing [dotfiles], run `mise bootstrap dotfiles status` and confirm every intended entry is listed (skipped entries are silently absent apart from a warning)"],"tags":["dotfiles","edits","path","validation"],"backgroundTag":"absolute-path-required","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}