jdx/mise · error

`schtasks ` failed

Error message

`schtasks {}` failed: {printed}

What it means

Applying start/stop changes to a Windows scheduled task shells out to schtasks; when the end (stop) invocation exits non-zero — and it is neither the benign SCHED_E_TASK_NOT_RUNNING code nor a locale-independent 'no-op' message — the apply step fails with the exact command and its printed output.

Solutions

  1. Read the printed schtasks output in the message for the root cause (access denied, task not found, etc.)
  2. Verify the task name/path with `schtasks /query`
  3. Re-run with elevated privileges if access was denied
  4. If the task is genuinely not running, treat it as no-op and skip the /end call

Example fix

// before
apply(stop("MyTask")) // fails: ERROR: Access is denied.
// after: run apply with an account that has rights on the task, or
schtasks /query /tn "MyTask" // confirm exact name first
Defensive patterns

Strategy: try-catch

Validate before calling

const q = await run('schtasks', ['/query', '/tn', taskName]);
if (q.status !== 0) throw new Error(`task ${taskName} not queryable: ${q.stdout}`);

Try / catch

try { await apply(change); } catch (e) { if (String(e).includes('`schtasks') ) { logSchtasksOutput(e.message); if (isAccessDenied(e.message)) requireElevation(); else if (isTaskNotFound(e.message)) recreateTask(); } else throw e; }

Prevention

When it happens

Trigger: Calling apply to stop (or restart) a scheduled task when `schtasks /end ...` returns a non-zero status other than 0x41306 (task not running) and its output doesn't match the known no-op error text.

Common situations: Task name typo or wrong path in schtasks arguments; task deleted by another process between checks; insufficient privileges to end a task running as another user; corrupted task definition.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/563322a48aa4f4d0. Report an issue: GitHub.

Appendix: source

Thrown at src/system/scheduled_tasks.rs:407

        }
        std::fs::write(&staging, &rendered)?;
        if let Err(err) = schtasks(&create).await {
            let _ = std::fs::remove_file(&staging);
            return Err(err);
        }
        // written, not renamed: a rename does not replace an existing
        // definition on Windows
        std::fs::write(&path, &rendered)?;
        let _ = std::fs::remove_file(&staging);
        if end_first {
            // it may have exited between the query and now: the HRESULT
            // says so in every locale; the message is matched as a fallback
            let (status, printed) = schtasks_output(&end).await?;
            if !status.success()
                && status.code() != Some(SCHED_E_TASK_NOT_RUNNING)
                && !end_error_is_noop(&printed)
            {
                bail!("`schtasks {}` failed: {printed}", shell_words::join(&end));
            }
        }
        if start {
            schtasks(&run).await?;
        }
    }
    Ok(())
}

/// Delete the task mise registered for `name`. Returns whether one existed.
pub(crate) async fn remove_task(name: &str, dry_run: bool) -> Result<bool> {
    let task = task_name(name);
    let path = definition_path(name);
    if !exists(name).await? {
        if path.exists() && !dry_run {
            std::fs::remove_file(&path)?;
        }
        return Ok(false);

View on GitHub (pinned to 533346cc37)