argoproj/argo-workflows · error
failed to wait for main container to complete: %w
Error message
failed to wait for main container to complete: %w
What it means
Wraps any failure from waitMainContainers in the emissary executor: the executor could not observe the main container(s) completing successfully while waiting on per-container exit-code files under /var/run/argo/ctr. The wrapped error tells why the wait failed (file never appears, read error, abnormal completion detection). context.Canceled is deliberately not wrapped, since cancellation is an intentional shutdown.
Source
Thrown at workflow/executor/executor.go:1378
// only monitor progress if both tick durations are >0
if we.annotationPatchTickDuration != 0 && we.readProgressFileTickDuration != 0 {
go we.monitorProgress(ctx, we.progressFile)
} else {
logger.WithField("annotationPatchTickDuration", we.annotationPatchTickDuration).WithField("readProgressFileTickDuration", we.readProgressFileTickDuration).Info(ctx, "monitoring progress disabled")
}
go we.monitorDeadline(ctx, containerNames)
err := retryutil.OnError(we.retryBackoff, func(err error) bool {
return errorsutil.IsTransientErr(ctx, err)
}, func() error {
return we.waitMainContainers(ctx, containerNames)
})
logger.WithError(err).Info(ctx, "Main container completed")
if err != nil && !errors.Is(err, context.Canceled) {
return fmt.Errorf("failed to wait for main container to complete: %w", err)
}
return nil
}
// waitMainContainers blocks until the given containers have completed, as
// signalled by the emissary's per-container exit-code files.
func (we *WorkflowExecutor) waitMainContainers(ctx context.Context, containerNames []string) error {
return we.RuntimeExecutor.Wait(ctx, containerNames)
}
// monitorProgress monitors for self-reported progress in the progressFile and patches the pod annotations with the parsed progress.
//
// The function watches the `progressFile` via inotify and re-parses the last line on every write.
// If the line matches `N/M`, will set the progress annotation to the parsed progress value.
// Every `annotationPatchTickDuration` the pod is patched with the updated annotations. This way the controller
// gets notified of new self reported progress.
func (we *WorkflowExecutor) monitorProgress(ctx context.Context, progressFile string) {
logger := logging.RequireLoggerFromContext(ctx)View on GitHub (pinned to 35bff19146)
Solutions
- Read the wrapped error (`%w` cause) to identify the specific failure — e.g. missing exit-code file vs read error
- Check the main container's status: `kubectl describe pod <pod>` and `kubectl logs <pod> -c main` for OOMKilled/eviction
- Verify /var/run/argo/ctr/<container>/exitcode exists and the emissary supervisor wrote it; check argoexec logs (`argo logs <workflow>`)
- Re-run the workflow; if reproducible on a node, cordon/inspect the node for disk or kubelet issues
- If it happens only at workflow shutdown, confirm the executor version matches (older versions had wait/teardown races)
Defensive patterns
Strategy: try-catch
Try / catch
if err != nil && !errors.Is(err, context.Canceled) {
var mainErr error
if errors.As(err, &mainErr) {
log.Printf("main container wait failed: %v", mainErr) // inspect wrapped cause
}
}
// then check the pod: kubectl describe pod & logs -c main for OOMKilled/eviction Prevention
- Always read the wrapped cause to distinguish missing exit-code file from read errors
- Check the main container for OOMKilled/evicted events when this appears
- Ensure /var/run/argo is on a writable, non-pressure volume
- Keep executor and controller versions in sync
When it happens
Trigger: During PostMain/`argoexec emissary` output capture, the exit-code file for a main container is missing or unreadable within the deadline, or the underlying wait reports an error other than context cancellation.
Common situations: Main container OOM-killed or node deleted so the exit-code file is never written; disk pressure wiping /var/run/argo; pod terminating mid-capture so the wait context is cancelled (this one is filtered, so seeing the wrapped error means non-cancel failure); race between emissary supervisor and wait stage on container teardown.
Related errors
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/b202f9613d251bcf.
Report an issue: GitHub.