argoproj/argo-workflows · error
failed to open process: %w
Error message
failed to open process: %w
What it means
Windows implementation of signalProcess: windows.OpenProcess(PROCESS_TERMINATE, ...) failed, so the executor could not get a handle to the target process in order to terminate/signal it. The underlying Windows error is wrapped — most commonly ERROR_ACCESS_DENIED (5) if the argoexec process lacks rights on the target, or the process already exited.
Source
Thrown at workflow/executor/osspecific/signal_windows.go:69
}
func Wait(process *os.Process) error {
stat, err := process.Wait()
if stat.ExitCode() != 0 {
return errors.NewExitErr(stat.ExitCode())
}
return err
}
// signalProcess sends the specified signal to a process.
//
// Code +/- copied from: https://github.com/microsoft/hcsshim/blob/1d69a9c658655b77dd4e5275bff99caad6b38416/internal/jobcontainers/process.go#L251
// License: MIT
// Author: Microsoft
func signalProcess(pid uint32, signal int) error {
hProc, err := windows.OpenProcess(windows.PROCESS_TERMINATE, true, pid)
if err != nil {
return fmt.Errorf("failed to open process: %w", err)
}
defer func() {
_ = windows.Close(hProc)
}()
if err := procCtrlRoutine.Find(); err != nil {
return fmt.Errorf("failed to load CtrlRoutine: %w", err)
}
threadHandle, err := createRemoteThread(hProc, nil, 0, procCtrlRoutine.Addr(), uintptr(signal), 0, nil)
if err != nil {
return fmt.Errorf("failed to open remote thread in target process %d: %w", pid, err)
}
defer func() {
_ = windows.Close(windows.Handle(threadHandle))
}()
return nil
}View on GitHub (pinned to 35bff19146)
Solutions
- Read the wrapped errno: ERROR_ACCESS_DENIED → permissions; ERROR_INVALID_PARAMETER → pid no longer exists
- Treat 'process not found' as success (the kill goal was already met) — check if the pid belonged to an already-completed main container
- Run argoexec with sufficient privileges in the container (job-container process access)
- Retry briefly before failing — there is an inherent race between reading the pid and the process exiting
Example fix
// caller-side tolerance
if err := osspecific.Kill(pid); err != nil {
if !strings.Contains(err.Error(), "The parameter is incorrect") { // already exited
return err
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// check the process exists before signaling
if h, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, pid); err != nil {
// already gone — skip kill
} else { windows.Close(h) } Try / catch
if err := osspecific.Kill(pid); err != nil {
if strings.Contains(err.Error(), "The parameter is incorrect") {
// process already exited; treat as success
} else {
return err
}
} Prevention
- Handle stale pids gracefully — race between pid capture and process exit is inherent
- Run argoexec with privileges granting PROCESS_TERMINATE on job-container processes
- Log and include the wrapped Windows errno for diagnosis
When it happens
Trigger: Kill() calls signalProcess(pid, sig) and the OS refuses the OpenProcess call — bad/already-reaped pid, insufficient privileges, or protected process.
Common situations: Target container process already exited (stale pid) so OpenProcess returns ERROR_INVALID_PARAMETER; argoexec service account lacking PROCESS_TERMINATE rights on the job-container process; Windows job-object/container hardening blocking cross-process access.
Related errors
- failed to load CtrlRoutine: %w
- failed to open remote thread in target process %d: %w
- cannot convert stdin to os.File, it was %T
- failed to read container args file %s: %w
- failed to unmarshal container args: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/d3ab12355a2371e1.
Report an issue: GitHub.