{"record":{"id":"31f675e30807d098","repo":"jdx/mise","slug":"scheduled-task-name-name-contains-characters-t","errorCode":null,"errorMessage":"scheduled task name {name:?} contains characters that cannot be queried","messagePattern":"scheduled task name (.+?) contains characters that cannot be queried","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/scheduled_tasks.rs","lineNumber":457,"sourceCode":"/// The task's state through the Task Scheduler API rather than the\n/// localized text `schtasks /query` prints. Prints `MISSING` for an\n/// unregistered task and the `TaskState` name otherwise. The name is\n/// embedded in the script (arguments after `-Command` are more command\n/// text, not `$args`); names are validated to letters, digits, `.`, `_`,\n/// and `-` before they get here.\nfn query_script(name: &str) -> String {\n    format!(\n        \"$t = Get-ScheduledTask -TaskPath '\\\\mise\\\\' -TaskName '{name}' -ErrorAction SilentlyContinue; if ($null -eq $t) {{ 'MISSING' }} else {{ $t.State.ToString() }}\"\n    )\n}\n\nasync fn query(task: &str) -> Result<Option<Query>> {\n    let name = task.strip_prefix(\"mise\\\\\").unwrap_or(task);\n    if !name\n        .chars()\n        .all(|c| c.is_ascii_alphanumeric() || matches!(c, '.' | '_' | '-'))\n    {\n        bail!(\"scheduled task name {name:?} contains characters that cannot be queried\");\n    }\n    let args = [\n        \"-NoProfile\".to_string(),\n        \"-NonInteractive\".to_string(),\n        \"-Command\".to_string(),\n        query_script(name),\n    ];\n    debug!(\"$ powershell {}\", shell_words::join(&args));\n    let mut cmd = tokio::process::Command::new(\"powershell.exe\");\n    cmd.args(&args)\n        .stdin(Stdio::null())\n        .stdout(Stdio::piped())\n        .stderr(Stdio::piped())\n        .kill_on_drop(true);\n    let output = tokio::time::timeout(SCHTASKS_TIMEOUT, cmd.output())\n        .await\n        .map_err(|_| eyre!(\"querying scheduled task {task} timed out\"))??;\n    if !output.status.success() {","sourceCodeStart":439,"sourceCodeEnd":475,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/scheduled_tasks.rs#L439-L475","documentation":"The query helper strips an optional 'mise\\' prefix and then validates that the remaining task name consists only of ASCII alphanumerics, '.', '_', or '-'. Names containing anything else (spaces, backslashes, shell metacharacters) cannot be safely passed to the PowerShell query script, so query refuses them before spawning a process.","triggerScenarios":"Calling status, exists, or apply with a task string whose name (after stripping the 'mise\\' prefix) contains characters outside [A-Za-z0-9._-] — e.g. spaces, '\\', '/', ':', quotes.","commonSituations":"Passing a full path like 'C:\\tasks\\my task' instead of just the task name; names with spaces copied from Task Scheduler; accidentally passing a command or extra arguments in the task string; non-ASCII characters in service names.","solutions":["Rename the task/service so its name uses only letters, digits, '.', '_', '-' (and rely on the 'mise\\\\' folder prefix for namespacing).","Strip any path/folder components before calling, keeping only the bare task name.","Quote/normalize user-supplied service names at a higher layer before they reach the task API.","If you control the name source (config), add a validation rule matching [A-Za-z0-9._-]+ there."],"exampleFix":"// before\nexists(\"mise\\\\My Service\")?; // space is not queryable\n// after\nexists(\"mise\\\\my-service\")?;","handlingStrategy":"validation","validationCode":"fn valid_task_name(name: &str) -> Result<(), String> {\n    let bare = name.strip_prefix(\"mise\\\\\").unwrap_or(name);\n    if !bare.chars().all(|c| c.is_ascii_alphanumeric() || matches!(c, '.' | '_' | '-')) {\n        return Err(format!(\"task name {bare:?} must match [A-Za-z0-9._-]+\"));\n    }\n    Ok(())\n}","typeGuard":"fn is_queryable_task_name(task: &str) -> bool {\n    let bare = task.strip_prefix(\"mise\\\\\").unwrap_or(task);\n    !bare.is_empty()\n        && bare.chars().all(|c| c.is_ascii_alphanumeric() || matches!(c, '.' | '_' | '-'))\n}","tryCatchPattern":null,"preventionTips":["Constrain service names at creation time to [A-Za-z0-9._-] so they are always queryable later","Never pass full paths, commands, or quoted names into the task API — only the bare task name","Sanitize user-supplied names in your config layer before they reach scheduled-task calls","Avoid spaces and non-ASCII characters in Windows service/task names"],"tags":["windows","scheduled-tasks","validation"],"backgroundTag":"invalid-identifier-format","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"}