{"record":{"id":"42dc2e23554ef579","repo":"jdx/mise","slug":"user-service-environment-key-key-cannot","errorCode":null,"errorMessage":"user service '{}': environment key {key:?} cannot be set through cmd.exe","messagePattern":"user service '(.+?)': environment key (.+?) cannot be set through cmd\\.exe","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/scheduled_tasks.rs","lineNumber":207,"sourceCode":"    }\n    out.push_str(\"    </Exec>\\n  </Actions>\\n\");\n    out.push_str(\"</Task>\\n\");\n    Ok(out)\n}\n\n/// Split the command line into the executable and its arguments. Task\n/// Scheduler has no environment block, so variables are set through\n/// `cmd.exe`, which reinterprets some characters; values that it would\n/// change are rejected rather than passed through differently.\nfn exec_action(request: &ScheduledTaskRequest) -> Result<(String, String)> {\n    let (program, args) = split_command(&request.command);\n    if request.environment.is_empty() {\n        return Ok((program, args));\n    }\n    let mut sets = vec![];\n    for (key, value) in &request.environment {\n        if key.is_empty() || key.contains(['=', '\"', '%', '\\n', '\\r']) {\n            bail!(\n                \"user service '{}': environment key {key:?} cannot be set through cmd.exe\",\n                request.name\n            );\n        }\n        if let Some(c) = value\n            .chars()\n            .find(|c| matches!(c, '\"' | '%' | '&' | '|' | '<' | '>' | '^' | '\\n' | '\\r'))\n        {\n            bail!(\n                \"user service '{}': environment value for {key} contains {c:?}, which cmd.exe would reinterpret; set it inside the program instead\",\n                request.name\n            );\n        }\n        sets.push(format!(\"set \\\"{key}={value}\\\"\"));\n    }\n    // the command line goes through cmd.exe too: what it would split or\n    // chain is rejected the same way, rather than run differently\n    if let Some(c) = format!(\"{program} {args}\")","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/scheduled_tasks.rs#L189-L225","documentation":"On Windows, when a user service request sets environment variables, they are injected by prefixing the command with `set \"KEY=VALUE\"` executed through cmd.exe. Some characters are illegal or structurally impossible in a cmd.exe environment-variable name, so exec_action rejects them at XML render time rather than emitting a broken service definition.","triggerScenarios":"Calling render_xml (via exec_action) for a scheduled-task/user-service whose request.environment contains a key that is empty or contains '=', a double quote, '%', a newline, or a carriage return.","commonSituations":"Copy-pasting env entries with stray whitespace or an embedded '=' from a .env file line; programmatic env maps that include empty-string keys; values loaded from files with CRLF endings where keys picked up a trailing '\\r'; templating that interpolates '%' into names.","solutions":["Remove or fix the offending environment key: it must be a non-empty name without '=', '\"', '%', or line breaks.","Strip whitespace/CR-LF from keys when loading environment from files or templates.","Pass such settings to the program another way (config file, arguments) instead of as a cmd.exe environment variable.","Validate the environment map before constructing the service request."],"exampleFix":"// before\nrequest.environment.insert(\"PATH=C:\\\\bin\".into(), \"x\".into());\n// after\nrequest.environment.insert(\"BIN_DIR\".into(), \"C:\\\\bin\".into());","handlingStrategy":"validation","validationCode":"fn valid_env_key(key: &str) -> Result<(), String> {\n    if key.is_empty() || key.contains(['=', '\"', '%', '\\n', '\\r']) {\n        return Err(format!(\"invalid env key: {key:?}\"));\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Trim and sanitize keys when loading env maps from files (strip BOM, CRLF, whitespace)","Never build keys by string concatenation of config fragments","Reject or log non-conforming keys at config-parse time, not at service-render time","Prefer simple [A-Za-z_][A-Za-z0-9_]* key names"],"tags":["windows","environment-variables","scheduled-tasks"],"backgroundTag":"invalid-argument-value","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"}