{"record":{"id":"15db8e49176feb93","repo":"jdx/mise","slug":"tracking-does-not-support-non-utf-8-filenames","errorCode":null,"errorMessage":"tracking does not support non-UTF-8 filenames","messagePattern":"tracking does not support non-UTF-8 filenames","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/tracked.rs","lineNumber":795,"sourceCode":"pub(crate) fn tree_path_to_display(tree_path: &str) -> String {\n    let (stem, rest) = tree_path.split_once('/').unwrap_or((tree_path, \"\"));\n    let root = stem.split('@').next().unwrap_or(stem);\n    if root == \"config\" {\n        display_path(global_config_dir().join(rest))\n    } else if root == \"home\" {\n        format!(\"~/{rest}\")\n    } else if let Some(rest) = tree_path.strip_prefix(\"fs/\") {\n        format!(\"/{rest}\")\n    } else {\n        tree_path.to_string()\n    }\n}\n\n/// Root aliases are portable through the home/config mapping. Aliases below\n/// those roots are not: canonicalizing them would silently change the enrolled\n/// destination on another machine. The leaf itself may still be a symlink.\npub(crate) fn ensure_portable_ancestors(path: &Path) -> Result<()> {\n    eyre::ensure!(\n        path.to_str().is_some(),\n        \"tracking does not support non-UTF-8 filenames\"\n    );\n    let roots = super::sync::layout::Roots::current();\n    let bases = [\n        dirs::HOME.to_path_buf(),\n        global_config_dir(),\n        roots.home,\n        roots.config_dir,\n    ];\n    let relative = |base: &Path| {\n        let mut components = path.components();\n        for expected in base.components() {\n            let actual = components.next()?;\n            if actual != expected\n                && !(cfg!(windows)\n                    && actual\n                        .as_os_str()","sourceCodeStart":777,"sourceCodeEnd":813,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/tracked.rs#L777-L813","documentation":"When tracking (enrolling) dotfiles into the history system, mise validates that the path can be represented as UTF-8 because paths are stored in config/aliases that require valid UTF-8. Non-UTF-8 filenames (raw bytes, legacy encodings) are rejected up front.","triggerScenarios":"Calling add_requests -> ensure_portable_ancestors with a Path containing invalid UTF-8 bytes (e.g. filenames created under a non-UTF-8 locale or random binary names).","commonSituations":"On Linux with a non-UTF-8 locale (LC_ALL=C), files created with odd byte sequences; files copied from archives or Windows with legacy encodings; accidentally enrolling a directory containing such files.","solutions":["Rename the offending file/dir to a valid UTF-8 name (e.g. with convmv)","Check your locale: use a UTF-8 locale (LANG=en_US.UTF-8) so new files are UTF-8","Exclude the non-UTF-8 path from tracking rather than enrolling its ancestors"],"exampleFix":"// before\nmise track ./files/  # contains byte-0xFF filename\n// after\nconvmv -f latin1 -t utf-8 -r ./files/\nmise track ./files/","handlingStrategy":"validation","validationCode":"if path.to_str().is_none() { eprintln!(\"skipping non-UTF-8 path: {}\", path.display()); }","typeGuard":"fn is_utf8_path(p: &Path) -> bool { p.to_str().is_some() }","tryCatchPattern":"match Err(m) if m.contains(\"non-UTF-8 filenames\") => { /* rename or skip the path */ }","preventionTips":["Use a UTF-8 locale on Linux/macOS","Fix non-UTF-8 filenames with convmv before enrolling dotfiles","List files with invalid encoding before tracking: find . | grep -P '[^\\x00-\\x7F]'"],"tags":["filesystem","encoding","utf-8","dotfiles"],"backgroundTag":"invalid-argument-format","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"}