{"record":{"id":"0a2ff7ab0b2d136b","repo":"jdx/mise","slug":"invalid-tool-path-s-contains-forbidden-charac","errorCode":null,"errorMessage":"invalid tool path {s:?}: contains forbidden character {c:?}","messagePattern":"invalid tool path (.+?): contains forbidden character (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/toolset/tool_request.rs","lineNumber":781,"sourceCode":"/// 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\n/// resolve; they keep being rejected, as they are today.\n#[cfg(windows)]\nfn windows_path_separators(s: &str) -> std::borrow::Cow<'_, str> {\n    if s.starts_with(r\"\\\\?\\\") || s.starts_with(r\"\\\\.\\\") {","sourceCodeStart":763,"sourceCodeEnd":799,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/toolset/tool_request.rs#L763-L799","documentation":"path: tool values have their own permissive but nonzero character allowlist (is_forbidden_path_char), since paths legitimately contain '/', spaces, etc. Any other forbidden character is rejected with a message naming the character, after Windows-specific backslash handling.","triggerScenarios":"A path: value containing a character rejected by is_forbidden_path_char (e.g. quotes, ';', '|', control characters, or a stray '\\' on non-Windows) passed through new_with_options.","commonSituations":"Shell interpolation injecting quotes/metacharacters into the path; path with unexpanded $VAR or ~ left literal in config; invisible characters from copy-paste; Windows-style backslash paths on Linux/macOS.","solutions":["Remove/replace the flagged character (it is named in the message).","Expand variables before writing config, or use mise templating/env correctly.","On Unix, convert Windows separators: C:\\tools\\node -> C:/tools/node (or a POSIX path)."],"exampleFix":"// before\nnode = \"path:$HOME/tools/'my node'\"\n// after\nnode = \"path:~/tools/my-node\"  # expand and avoid quote characters","handlingStrategy":"validation","validationCode":"function validPath(p) {\n  return typeof p === 'string' && p.length > 0 && !/[\\'\";$|&`<>]/.test(p);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Expand $VAR and ~ before writing path: values into config.","Convert Windows backslash paths on Unix hosts.","Re-type suspicious paths instead of pasting to avoid invisible characters."],"tags":["mise","validation","path","input-validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}