{"record":{"id":"e9dd19a6f57649fb","repo":"jdx/mise","slug":"history-cannot-represent-a-non-utf-8-filename-ref","errorCode":null,"errorMessage":"history cannot represent a non-UTF-8 filename; refusing to change its bytes","messagePattern":"history cannot represent a non-UTF-8 filename; refusing to change its bytes","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/tracked.rs","lineNumber":381,"sourceCode":"        // a hidden local-only history. Explicit encryption permits key files\n        // to be tracked without storing their plaintext.\n        walk.files.retain(|path, (_, policy)| {\n            if let Some(reason) = capture_exclusion(path, policy) {\n                walk.omitted.push(PathReason {\n                    path: display_path(path),\n                    reason: reason.into(),\n                });\n                false\n            } else {\n                true\n            }\n        });\n        walk.entries = set.entries.clone();\n        let config = normalize(&global_config_dir());\n        let mut roots: BTreeMap<String, CaptureRoot> = BTreeMap::new();\n        for (path, (owner, _)) in &walk.files {\n            if path.to_str().is_none() {\n                eyre::bail!(\n                    \"history cannot represent a non-UTF-8 filename; refusing to change its bytes\"\n                );\n            }\n            let (label, base, relative) = if let Ok(relative) = path.strip_prefix(&config) {\n                (\"config\", config.clone(), relative.to_path_buf())\n            } else if let Ok(relative) = path.strip_prefix(&home) {\n                (\"home\", home.clone(), relative.to_path_buf())\n            } else {\n                (\n                    \"fs\",\n                    PathBuf::from(std::path::MAIN_SEPARATOR.to_string()),\n                    path.components()\n                        .filter(|c| matches!(c, Component::Normal(_)))\n                        .collect(),\n                )\n            };\n            let label = walk.entries[*owner]\n                .variant","sourceCodeStart":363,"sourceCodeEnd":399,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/tracked.rs#L363-L399","documentation":"During the history walk, every captured file path is converted to a Rust str to be keyed into capture roots. If a filename is not valid UTF-8 (raw bytes on disk, e.g. from a non-UTF-8 locale filesystem), the history layer refuses to record it rather than silently corrupting or transcoding its bytes, so it aborts the walk.","triggerScenarios":"Running history tracking (walk, invoked via attempt_locked/live_tree/unsaved_paths) over a directory containing a file or directory whose name is not valid UTF-8, e.g. created by a tool using raw bytes or a legacy encoding.","commonSituations":"Filenames created on Linux with non-UTF-8 locales (Latin-1 bytes, GBK, etc.), files unpacked from old archives, or paths produced by legacy scripts; user then enables mise history tracking over their home directory and the walk hits the bad name.","solutions":["Find and rename the offending non-UTF-8 filename to a UTF-8 name (e.g. with `convmv --notest -f latin1 -t utf8 -r .` or `find . | LC_ALL=C grep -P '[^\\x00-\\x7F]'` to locate it).","Move the non-UTF-8 file outside of the tracked roots (home or the mise config directory) so the walk no longer encounters it.","Delete the offending file if it is no longer needed.","If you cannot fix the filename, file an issue to request a skip-with-warning mode instead of a hard abort."],"exampleFix":"// before: file named 'r\\e9sum\\e9.txt' stored as Latin-1 bytes in a tracked directory\n// after\nconvmv -f latin1 -t utf8 --notest 'r\\e9sum\\e9.txt'  # now valid UTF-8: 'résumé.txt'","handlingStrategy":"validation","validationCode":"// before enabling history tracking over a directory, scan for non-UTF-8 names\nuse std::path::Path;\nfn has_non_utf8_names(root: &Path) -> std::io::Result<bool> {\n    let mut bad = false;\n    for entry in walkdir_like(root) {\n        if entry.path().to_str().is_none() {\n            bad = true;\n            eprintln!(\"non-UTF-8 filename: {:?}\", entry.path());\n        }\n    }\n    Ok(bad)\n}","typeGuard":"fn is_utf8_path(p: &std::path::Path) -> bool { p.to_str().is_some() }","tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"non-UTF-8 filename\") => {\n        eprintln!(\"rename non-UTF-8 files under tracked roots before tracking\");\n    }\n    other => other?,\n}","preventionTips":["Keep filenames ASCII or valid UTF-8, especially in directories you track","Run `find . | grep -P '[^\\x00-\\x7F]'` occasionally to spot odd names","Use convmv when unpacking archives from other encodings","Avoid legacy-locale tools (tar with raw byte names) writing into your home directory"],"tags":["filesystem","encoding","utf-8","history-tracking"],"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-14T05:17:10.506Z"}