jdx/mise · error

tracking does not support non-UTF-8 filenames

Error message

tracking does not support non-UTF-8 filenames

What it means

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.

Source

Thrown at src/system/history/tracked.rs:795

pub(crate) fn tree_path_to_display(tree_path: &str) -> String {
    let (stem, rest) = tree_path.split_once('/').unwrap_or((tree_path, ""));
    let root = stem.split('@').next().unwrap_or(stem);
    if root == "config" {
        display_path(global_config_dir().join(rest))
    } else if root == "home" {
        format!("~/{rest}")
    } else if let Some(rest) = tree_path.strip_prefix("fs/") {
        format!("/{rest}")
    } else {
        tree_path.to_string()
    }
}

/// Root aliases are portable through the home/config mapping. Aliases below
/// those roots are not: canonicalizing them would silently change the enrolled
/// destination on another machine. The leaf itself may still be a symlink.
pub(crate) fn ensure_portable_ancestors(path: &Path) -> Result<()> {
    eyre::ensure!(
        path.to_str().is_some(),
        "tracking does not support non-UTF-8 filenames"
    );
    let roots = super::sync::layout::Roots::current();
    let bases = [
        dirs::HOME.to_path_buf(),
        global_config_dir(),
        roots.home,
        roots.config_dir,
    ];
    let relative = |base: &Path| {
        let mut components = path.components();
        for expected in base.components() {
            let actual = components.next()?;
            if actual != expected
                && !(cfg!(windows)
                    && actual
                        .as_os_str()

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Rename the offending file/dir to a valid UTF-8 name (e.g. with convmv)
  2. Check your locale: use a UTF-8 locale (LANG=en_US.UTF-8) so new files are UTF-8
  3. Exclude the non-UTF-8 path from tracking rather than enrolling its ancestors

Example fix

// before
mise track ./files/  # contains byte-0xFF filename
// after
convmv -f latin1 -t utf-8 -r ./files/
mise track ./files/
Defensive patterns

Strategy: validation

Validate before calling

if path.to_str().is_none() { eprintln!("skipping non-UTF-8 path: {}", path.display()); }

Type guard

fn is_utf8_path(p: &Path) -> bool { p.to_str().is_some() }

Try / catch

match Err(m) if m.contains("non-UTF-8 filenames") => { /* rename or skip the path */ }

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/15db8e49176feb93. Report an issue: GitHub.