{"record":{"id":"e3abcb2872ff2666","repo":"jdx/mise","slug":"invalid-tool-path-s-extended-length-and-devic-e3abcb","errorCode":null,"errorMessage":"invalid tool path {s:?}: extended-length and device paths (\\\\?\\, \\\\.\\) are not supported","messagePattern":"invalid tool path (.+?): extended-length and device paths \\(\\\\\\\\\\?\\\\, \\\\\\\\\\.\\\\\\) are not supported","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/toolset/tool_request.rs","lineNumber":687,"sourceCode":"/// The list is written for a POSIX shell, which is why `\\` is on it. On Windows `\\` is a path\n/// separator instead, so it is rewritten by [`windows_path_separators`] before it gets here rather\n/// than being allowed through — see that function. The shell those hooks run through there is\n/// `cmd.exe`, whose metacharacters are a different set, so a few more are rejected on Windows —\n/// see [`is_forbidden_path_char`].\nfn validate_path_string(s: &str) -> Result<()> {\n    if s.is_empty() {\n        return Ok(());\n    }\n    if let Some(c) = s.chars().find(|c| {\n        // Allow newlines/tabs/etc. in paths is still bad — keep control-char\n        // and quote/expansion rejection, but allow `/` since paths need it.\n        is_forbidden_path_char(*c)\n    }) {\n        // The only `\\` that survives the rewrite is an extended-length or device prefix, so say\n        // what is actually wrong instead of naming a character the user cannot avoid.\n        #[cfg(windows)]\n        if c == '\\\\' {\n            bail!(\n                \"invalid tool path {s:?}: extended-length and device paths (\\\\\\\\?\\\\, \\\\\\\\.\\\\) are not supported\"\n            );\n        }\n        bail!(\"invalid tool path {s:?}: contains forbidden character {c:?}\");\n    }\n    Ok(())\n}\n\n/// Rewrite `\\` to `/` in a `path:` value on Windows.\n///\n/// `\\` is the path separator there, not a shell metacharacter, so [`validate_path_string`] used to\n/// reject every native path — anything copied out of Explorer or printed by `pwd`. Win32 accepts\n/// `/` wherever it accepts `\\`, so rewriting is what makes those usable *without* letting a `\\`\n/// reach a vfox hook's `ctx.rootPath`, which is the thing the list exists to prevent (#9814). The\n/// alternative — dropping `\\` from the list on Windows — would have weakened that.\n///\n/// Extended-length and device prefixes (`\\\\?\\`, `\\\\.\\`) are left alone. Those are the one place\n/// Windows does not accept `/`, so rewriting would hand back a path that looks right and does not","sourceCodeStart":669,"sourceCodeEnd":705,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/toolset/tool_request.rs#L669-L705","documentation":"validate_path_string validates `path:` tool values. On Windows, the only backslash surviving the '\\'→'/' rewrite is an extended-length (\\\\?\\) or device (\\\\.\\) prefix, so this arm reports those prefixes as unsupported rather than blaming an unfixable character. mise throws this during ToolRequest construction.","triggerScenarios":"On Windows, a tool entry like `\"path:C:\\\\?\\\\C:\\\\huge\\\\dir\"` or `path:\\\\.\\\\device...` in mise.toml/.tool-versions or on the CLI.","commonSituations":"Users copying paths from Windows tooling that returns extended-length paths for long directories, or referencing device paths for drives/devices that mise cannot install tools from.","solutions":["Remove the \\\\?\\ prefix and reference the directory with a normal absolute path (`path:C:/tools/dir` or `path:C:\\tools\\dir`).","Shorten the path (or use a junction/subst drive) so the extended-length prefix is unnecessary.","Avoid device paths (\\\\.\\) — mise cannot treat them as a tool source; point at a real filesystem directory instead."],"exampleFix":"// before (Windows mise.toml)\n[tools]\n\"path:C:\\\\?\\\\C:\\\\very\\\\long\\\\path\\\\tools\" = \"1\"\n// after\n[tools]\n\"path:C:\\\\tools\" = \"1\"","handlingStrategy":"validation","validationCode":"function isPlainWindowsPath(p) {\n  return typeof p === 'string' && !p.startsWith('\\\\\\\\?\\\\') && !p.startsWith('\\\\\\\\.\\\\');\n}\nif (!isPlainWindowsPath(p)) throw new Error('extended-length/device paths are not supported');","typeGuard":"function isNormalPath(v) { return typeof v === 'string' && !/^\\\\\\\\[?.]\\\\/.test(v); }","tryCatchPattern":null,"preventionTips":["Strip \\\\?\\ prefixes when copying paths from Windows APIs or long-path tooling.","Keep tool directories under a short path to avoid needing extended-length syntax.","Never reference device paths (\\\\.\\) as tool sources."],"tags":["windows","path","validation","unsupported-platform"],"backgroundTag":"unsupported-operation","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"}