jdx/mise · error

invalid completion specification path

Error message

invalid completion specification path

What it means

decode_spec_path decodes a base64url-encoded path embedded in a generated completion loader back into a PathBuf. On Windows the encoding is UTF-16LE (each character = 2 bytes); if the decoded byte vector has an odd length, it cannot be a valid UTF-16 sequence, so decoding would corrupt the path and mise bails instead. This guards against a truncated or hand-mangled encoded string.

Source

Thrown at src/packslip/completions.rs:43

            .flat_map(u16::to_le_bytes)
            .collect()
    };
    base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(bytes)
}

pub(crate) fn decode_spec_path(encoded: &str) -> eyre::Result<std::path::PathBuf> {
    use base64::Engine;
    let bytes = base64::engine::general_purpose::URL_SAFE_NO_PAD.decode(encoded)?;
    #[cfg(unix)]
    let path = {
        use std::os::unix::ffi::OsStringExt;
        std::ffi::OsString::from_vec(bytes)
    };
    #[cfg(windows)]
    let path = {
        use std::os::windows::ffi::OsStringExt;
        if !bytes.len().is_multiple_of(2) {
            eyre::bail!("invalid completion specification path");
        }
        let wide: Vec<_> = bytes
            .chunks_exact(2)
            .map(|b| u16::from_le_bytes([b[0], b[1]]))
            .collect();
        std::ffi::OsString::from_wide(&wide)
    };
    Ok(path.into())
}

pub(crate) fn clear(shell: &str) -> &'static str {
    match shell {
        "bash" | "zsh" => {
            "if typeset -f __mise_clear_completions >/dev/null; then __mise_clear_completions; unset -f __mise_clear_completions; fi\n"
        }
        "fish" => {
            "if functions -q __mise_clear_completions; __mise_clear_completions; functions -e __mise_clear_completions; end\n"
        }

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Regenerate the completion loader: rerun activation (`mise activate <shell>`) or `mise completion <shell> --tool <tool>` so the encoded path is rebuilt.
  2. Do not hand-edit the base64 constant inside the loader script; replace the whole script instead.
  3. Verify the loader file was not truncated by your editor or shell config tooling (check for intact quotes and length).

Example fix

// before: hand-edited loader constant
__usage_complete_path aGVsbG8gd29ybA
// after: regenerate
mise activate pwsh  # rewrites the loader with a fresh, intact encoded path
Defensive patterns

Strategy: try-catch

Validate before calling

fn valid_b64url_len(s: &str) -> bool {
    base64::engine::general_purpose::URL_SAFE_NO_PAD.decode(s)
        .map(|b| b.len() % 2 == 0)
        .unwrap_or(false) // on Windows targets
}

Type guard

fn decodable_spec_path(encoded: &str) -> bool { decode_spec_path(encoded).is_ok() }

Try / catch

match decode_spec_path(&encoded) {
    Ok(path) => load_spec(&path),
    Err(e) => {
        eprintln!("loader constant corrupt ({e}); regenerating");
        regenerate_loader(shell, tool)?;
    }
}

Prevention

When it happens

Trigger: A completion loader script (generated by derive_from_spec embedding the base64url spec path) whose encoded path constant was truncated, edited, or produced by an encoder that dropped a byte — decode yields an odd-length byte vector on Windows.

Common situations: Shell config mangling the generated script (line wrapping, editors stripping characters); copying a loader between machines with a corrupted constant; an old loader after a mise change in encoding.

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/a720b68adf6382c3. Report an issue: GitHub.