clash-verge-rev/clash-verge-rev · error · anyhow::Error

failed to create {} task: {}

Error message

failed to create {} task: {}

What it means

create_task() writes the XML and invokes `schtasks /Create /TN <name> /XML <path> /F`. /F forces overwrite of an existing task, so a non-zero exit means schtasks rejected the task definition or refused the operation. The error carries output_message() (decoded stdout/stderr) so the OS reason is visible.

Source

Thrown at src-tauri/src/utils/schtasks.rs:285

        cmd.args(["/Query", "/TN", mode.name()]);
        cmd
    })?;

    Ok(output.status.success())
}

pub fn create_task(mode: TaskMode) -> Result<()> {
    let task_xml_path = write_task_xml(mode)?;
    let output = schtasks_output({
        let mut cmd = Command::new("schtasks");
        cmd.args(["/Create", "/TN", mode.name(), "/XML"]);
        cmd.arg(&task_xml_path);
        cmd.arg("/F");
        cmd
    })?;

    if !output.status.success() {
        return Err(anyhow!(
            "failed to create {} task: {}",
            mode.label(),
            output_message(&output)
        ));
    }

    logging!(info, Type::Setup, "Created {} auto-launch task", mode.label());
    Ok(())
}

pub fn remove_task(mode: TaskMode) -> Result<()> {
    let output = schtasks_output({
        let mut cmd = Command::new("schtasks");
        cmd.args(["/Delete", "/TN", mode.name(), "/F"]);
        cmd
    })?;

    if output.status.success() {

View on GitHub (pinned to 5cad0f2799)

Solutions

  1. If is_admin was true, re-launch the app with 'Run as administrator' before toggling auto-launch.
  2. Open Task Scheduler GUI, look for residual 'Clash Verge' / 'Clash Verge (Admin)' tasks, delete them, then retry.
  3. Verify get_task_user_id() resolves to DOMAIN\\user that matches the account that will log in.
  4. Run `schtasks /Create /TN "Clash Verge" /XML <path> /F` manually in cmd to capture the exact reason from schtasks.

Example fix

// before - unelevated process tries admin task
create_task(TaskMode::Admin)?;
// after - refuse admin task creation without elevation
if is_admin && !is_elevated() {
    return Err(anyhow!("re-launch as administrator to create the admin auto-launch task"));
}
create_task(TaskMode::Admin)?;
Defensive patterns

Strategy: validation

Validate before calling

#[cfg(windows)]
fn is_elevated() -> bool {
    use windows::Win32::Security::{GetTokenInformation, TokenElevation, TOKEN_ELEVATION, TOKEN_QUERY};
    use windows::Win32::System::Threading::OpenProcessToken;
    use windows::Win32::Foundation::{CloseHandle, HANDLE};
    // open current process token, query TokenElevation, return elevation.Level != 0
    true // (body abbreviated)
}
if is_admin && !is_elevated() { return Err(anyhow!("elevation required")); }

Try / catch

if let Err(e) = create_task(target) {
    let msg = e.to_string().to_lowercase();
    if msg.contains("access") || msg.contains("admin") {
        // surface an elevation prompt to the user
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Creating the Admin task while running unelevated (RunLevel HighestAvailable denied); USERNAME/USERDOMAIN producing a UserId the scheduler will not accept (e.g., MicrosoftAccount\foo); XML schema violation across Windows versions; task name conflicts with a task owned by another principal; Task Scheduler service stopped or corrupt.

Common situations: User toggled 'auto-launch as admin' without UAC elevation; account renamed after the task was first created; domain account where the NetBIOS domain differs from USERDOMAIN; localized Windows where the principal format differs.

Related errors


AI-assisted analysis of clash-verge-rev/clash-verge-rev@5cad0f2799 (2026-08-12). Data as JSON: /api/errors/7753c8114d47ea20. Report an issue: GitHub.