argoproj/argo-workflows · error

%w

Error message

%w

What it means

The `argoexec supervisor` cobra command (init-less pod layout) wraps any error from supervisorContainer with fmt.Errorf("%w", err). This is a transparent pass-through wrapper: no message text is added and the original cause is preserved for errors.Is/errors.As. The real failure is inside the supervisor container lifecycle (prepare main, readiness signaling, or output collection).

Source

Thrown at cmd/argoexec/commands/supervisor.go:51

	supervisorHeartbeatInterval = 5 * time.Second
	// supervisorHeartbeatTimeout is how long main tolerates a status marker that
	// has neither appeared nor advanced before presuming the supervisor dead.
	// Generously larger than the interval so a GC pause or CPU starvation in the
	// supervisor doesn't trigger a false-positive death.
	supervisorHeartbeatTimeout = 30 * time.Second
	// supervisorStatusPollInterval is how often main re-checks the marker's
	// freshness. inotify delivers the terminal READY/FAILED write promptly; this
	// poll exists only to notice the *absence* of heartbeats, which inotify can't.
	supervisorStatusPollInterval = 2 * time.Second
)

func NewSupervisorCommand() *cobra.Command {
	command := cobra.Command{
		Use:   "supervisor",
		Short: "init-less auxiliary: prepare main, signal readiness, then collect outputs",
		RunE: func(cmd *cobra.Command, args []string) error {
			if err := supervisorContainer(cmd.Context()); err != nil {
				return fmt.Errorf("%w", err)
			}
			return nil
		},
	}
	return &command
}

func supervisorContainer(ctx context.Context) error {
	return runAuxiliaryContainer(ctx,
		func(we *wfexecutor.WorkflowExecutor, ctx context.Context) (context.Context, trace.Span) {
			return we.Tracing.StartRunSupervisorContainer(ctx, we.WorkflowName(), we.Namespace)
		},
		func(ctx, bgCtx context.Context, we *wfexecutor.WorkflowExecutor) error {
			// Heartbeat the status marker so main's emissary can tell a live (but
			// slow) supervisor from a dead one, rather than blocking to the pod
			// deadline. The initial write also overwrites any stale marker from a
			// prior attempt. Stop the heartbeat before the terminal write so no
			// heartbeat races it on the same path.

View on GitHub (pinned to 35bff19146)

Solutions

  1. Read the wrapped cause after this error for the concrete failure inside supervisorContainer
  2. Verify the /var/run/argo shared volume is mounted in both main and supervisor containers
  3. Check that the template is present at /var/run/argo/template and readable by argoexec
  4. Confirm the pod uses a compatible executor version for init-less (beta) pods
Defensive patterns

Strategy: try-catch

Validate before calling

// check pod wiring before init-less runs:
// kubectl exec <pod> -c main -- ls -l /var/run/argo/template
// kubectl exec <pod> -c main -- mount | grep argo

Try / catch

// pass-through wrapper; unwrap at call site for the real cause
if err := supervisorContainer(ctx); err != nil {
    return fmt.Errorf("%w", err) // errors.Unwrap to reach the root cause
}

Prevention

When it happens

Trigger: Running `argoexec supervisor` where supervisorContainer fails — e.g. the template cannot be read from /var/run/argo/template, the shared /var/run/argo mount is broken, or the main container's exit/status capture fails.

Common situations: Init-less (supervisor) workflows where the shared volume mount between main and supervisor containers is misconfigured; unreadable workflow template secret/ConfigMap; permission problems on /var/run/argo.

Related errors


AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03). Data as JSON: /api/errors/46a52f3b994e8cc5. Report an issue: GitHub.