jdx/mise · error
could not find the suspended description command's primary t
Error message
could not find the suspended description command's primary thread
What it means
Thrown by `WindowsJob::start` when, after creating the suspended description command process inside a Windows job object, a Toolhelp32 snapshot traversal (Thread32First/Thread32Next) finds no thread to identify as the command's primary thread. Without that thread handle the library cannot resume/track the process, so it aborts startup.
Source
Thrown at src/system/history/describe_command/windows_job.rs:87
while found {
if entry.th32OwnerProcessID == child.id() {
// SAFETY: request only resume access to the child's thread.
let thread = unsafe { OpenThread(THREAD_SUSPEND_RESUME, 0, entry.th32ThreadID) };
if thread.is_null() {
return Err(std::io::Error::last_os_error().into());
}
// SAFETY: the returned handle is valid and uniquely owned.
let thread = unsafe { OwnedHandle::from_raw_handle(thread) };
// SAFETY: the child is already assigned to our kill-on-close job.
if unsafe { ResumeThread(thread.as_raw_handle()) } == u32::MAX {
return Err(std::io::Error::last_os_error().into());
}
return Ok(());
}
// SAFETY: the snapshot and writable entry remain valid.
found = unsafe { Thread32Next(snapshot.as_raw_handle(), &mut entry) } != 0;
}
bail!("could not find the suspended description command's primary thread")
}
pub(super) fn kill(&self) {
// SAFETY: the owned handle always refers to this command's job.
unsafe { TerminateJobObject(self.0.as_raw_handle(), 1) };
}
}
pub(super) fn spawn(command: &mut Command) -> Result<(Child, Job)> {
let job = Job::new()?;
command.creation_flags(CREATE_SUSPENDED);
let mut child = command.spawn()?;
if let Err(error) = job.start(&child) {
// A failure must not leave either a suspended child or an unowned tree.
let _ = child.kill();
let _ = child.wait();
return Err(error);
}View on GitHub (pinned to afd2eddd3a)
Solutions
- Retry the description command; a transient race with process startup is the usual cause.
- Check whether antivirus/EDR is killing freshly spawned processes and add an exclusion for the mise binary.
- Verify the command itself does not exit instantly with an error before threads can be enumerated.
- Report a bug if reproducible: the snapshot loop should handle this process-creation race internally.
Defensive patterns
Strategy: retry
Try / catch
// on Err("could not find ... primary thread") on Windows: retry once
// before assuming the command itself is broken Prevention
- Keep antivirus exclusions for the tool binary.
- Avoid commands that exit instantly before threads enumerate.
- Retry transient Windows process-start failures once.
When it happens
Trigger: On Windows only: process creation succeeded but the snapshot enumeration returned no threads belonging to the new process — typically a race where the process exited before enumeration, or snapshot creation raced process initialization.
Common situations: Antivirus or security software terminating newly spawned processes; extremely fast-failing description commands on Windows; system resource pressure making CreateToolhelp32Snapshot return a stale/empty snapshot.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- `schtasks {}` failed: {printed}
- querying scheduled task {task} failed: {}
- TEMP is too long to replace mise.exe safely ({len} UTF-16 co
- Ruby engine '{}' is not supported on Windows. Only standard
- only available on unix
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/9727fe05d983121f.
Report an issue: GitHub.