jdx/mise · error

user service '{}': the command contains {c:?}, which cmd.exe

Error message

user service '{}': the command contains {c:?}, which cmd.exe would reinterpret when `environment` is set; move it into a script

What it means

When a user service defines environment variables, the whole command line (program + args) is executed through cmd.exe, so characters that cmd treats specially — %, &, |, <, >, ^, and line breaks — would change the meaning of the command. exec_action rejects such command lines up front instead of letting cmd.exe reinterpret them.

Source

Thrown at src/system/scheduled_tasks.rs:229

        }
        if let Some(c) = value
            .chars()
            .find(|c| matches!(c, '"' | '%' | '&' | '|' | '<' | '>' | '^' | '\n' | '\r'))
        {
            bail!(
                "user service '{}': environment value for {key} contains {c:?}, which cmd.exe would reinterpret; set it inside the program instead",
                request.name
            );
        }
        sets.push(format!("set \"{key}={value}\""));
    }
    // the command line goes through cmd.exe too: what it would split or
    // chain is rejected the same way, rather than run differently
    if let Some(c) = format!("{program} {args}")
        .chars()
        .find(|c| matches!(c, '%' | '&' | '|' | '<' | '>' | '^' | '\n' | '\r'))
    {
        bail!(
            "user service '{}': the command contains {c:?}, which cmd.exe would reinterpret when `environment` is set; move it into a script",
            request.name
        );
    }
    let program = if program.contains(char::is_whitespace) {
        format!("\"{program}\"")
    } else {
        program
    };
    let rest = if args.is_empty() {
        program
    } else {
        format!("{program} {args}")
    };
    Ok((
        "cmd.exe".to_string(),
        format!("/c {} && {rest}", sets.join(" && ")),
    ))

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Move the redirection/piping/expansion into a wrapper script (.cmd/.ps1) and point the service at that script.
  2. Remove cmd-specific metacharacters from program/args; perform redirects inside the program (e.g. built-in logging).
  3. If env vars are not actually needed, unset request.environment so the command no longer runs through cmd.exe.
  4. Replace '%' expansions with explicit absolute paths.

Example fix

// before
request.environment.insert("MODE".into(), "prod".into());
request.args = ["/c", "app.exe > out.log"].into();
// after
request.program = "C:\\svc\\run.cmd".into(); // script contains the redirect
request.args = [].into();
Defensive patterns

Strategy: validation

Validate before calling

fn cmd_safe_command(program: &str, args: &[String]) -> Result<(), String> {
    let line = format!("{program} {}", args.join(" "));
    if let Some(c) = line.chars().find(|c| matches!(c, '%' | '&' | '|' | '<' | '>' | '^' | '\n' | '\r')) {
        return Err(format!("command contains cmd.exe metachar {c:?}; use a wrapper script"));
    }
    Ok(())
}

Prevention

When it happens

Trigger: Calling render_xml (via exec_action) for a user service that sets request.environment and whose formatted "{program} {args}" string contains '%', '&', '|', '<', '>', '^', '\n', or '\r'. Note this check only runs when environment is set; without env vars the command bypasses cmd.exe.

Common situations: Redirects or pipes written directly into the service command ('app.exe > log.txt'); args containing '&' (URLs, background syntax); '%APPDATA%' style expansion expected in the command; multi-line commands pasted from scripts.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/a61ad80f1aeebc93. Report an issue: GitHub.