jdx/mise · error

--localized-dir {raw:?} cannot be carried to Windows: {bad:?

Error message

--localized-dir {raw:?} cannot be carried to Windows: {bad:?} is not allowed in a path component there, so the generated launcher could not create the directory. Drop --windows, or pick a name Windows accepts.

What it means

With `--localize`, `mise generate bootstrap --windows` embeds --localized-dir into a .cmd launcher that mkdir's it (relative dirs are joined to %project_dir%). Windows forbids < > : " | ? * inside a path component — and a component like `C:foo` is drive-relative there, not a path — so the generator refuses the value rather than emitting a launcher that would fail later on the contributor's Windows machine.

Source

Thrown at src/cli/generate/bootstrap.rs:242

    rest.trim_start_matches(['\\', '/'])
}

/// The `localized_dir` value for the batch script — the same two rules the bash branch applies:
/// escape the value, and join it to the project directory only when it is relative.
///
/// Refuses a value Windows could not hold rather than emitting one. A directory named `C:foo` is
/// ordinary on Linux and the bash half installs into it happily, but on Windows `C:foo` is
/// drive-*relative*, so `%project_dir%\C:foo` is not a path at all and `mkdir` fails — on the
/// contributor's machine, not on the machine that generated the file. Calling it rooted instead
/// would be worse: that drops `%project_dir%\` and installs wherever cmd's per-drive working
/// directory happens to point, silently diverging from the bash half.
fn windows_localized_dir(dir: &Path) -> Result<String> {
    let raw = dir.to_string_lossy();
    if let Some(bad) = windows_path_components(&raw)
        .chars()
        .find(|c| WINDOWS_FORBIDDEN_IN_COMPONENT.contains(c))
    {
        bail!(
            "--localized-dir {raw:?} cannot be carried to Windows: {bad:?} is not allowed in a \
             path component there, so the generated launcher could not create the directory. \
             Drop --windows, or pick a name Windows accepts."
        );
    }
    let escaped = cmd_escape(&raw);
    match is_windows_absolute(&escaped) {
        true => Ok(escaped),
        false => Ok(format!(r"%project_dir%\{escaped}")),
    }
}

/// Escape a value for interpolation into a `set "var=…"` line in the launcher.
///
/// Only `%` needs it. The script keeps delayed expansion off, so `!` is already an ordinary
/// character there — measured: with it off, `set "d=…\p6-od!d"` followed by `mkdir "%d%"` creates
/// `p6-od!d`, and with it on the same two lines create `p6-odd`. A raw `%` would still be read at
/// parse time, so with `x` set a directory named `my%x%dir` becomes `myCLOBBEREDdir`.

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Pick a --localized-dir whose components avoid < > : " | ? * (e.g. .mise-local, cache-dev)
  2. Drop `--windows` to generate only the bash bootstrap, which accepts the Unix-legal name
  3. Keep the odd name for the Unix script and generate the Windows launcher separately with a Windows-safe directory

Example fix

# before
mise generate bootstrap --localize --localized-dir 'cache:dev' --windows
# error: ':' is not allowed in a path component there

# after
mise generate bootstrap --localize --localized-dir 'cache-dev' --windows
Defensive patterns

Strategy: validation

Validate before calling

#!/bin/bash
# reject Windows-forbidden chars before generating
if printf %s "$LOCALIZED_DIR" | grep -q '[<>:"|?*]'; then
  echo "--localized-dir '$LOCALIZED_DIR' cannot be carried to Windows" >&2
  exit 1
fi
mise generate bootstrap --localize --localized-dir "$LOCALIZED_DIR" --windows

Type guard

windows_safe_dir() {
  # returns 0 when every component avoids < > : " | ? *
  case "$1" in
    *[\<\>:\"\|\?*]*) return 1 ;;
    *) return 0 ;;
  esac
}

Prevention

When it happens

Trigger: `mise generate bootstrap --localize --localized-dir <dir> --windows` where any component of <dir> contains one of the seven forbidden characters (a colon is the common trap: names like `C:foo` or `cache:dev` are legal on Linux/macOS but unusable on Windows).

Common situations: Unix project localizing into a timestamp/URL-derived name containing colons (`backup:2026`, `https://` fragments); passing a drive-relative Windows path by mistake; script composing the dir from unvalidated input.

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/be7a6086857d838e. Report an issue: GitHub.