argoproj/argo-workflows · error

invalid timeout format %w

Error message

invalid timeout format %w

What it means

getTimeoutAsDeadline converts a template's timeout value into a deadline by parsing it with wfv1.ParseStringToDuration. If the timeout string is not a valid duration, the function returns 'invalid timeout format %w' wrapping the parse error. This is a spec/config validation failure: the template's Timeout (or the value passed to deadline computation) is malformed, so the controller cannot compute when the step should be killed.

Source

Thrown at workflow/controller/operator.go:2678

	}

	woc.log.WithField("nodeName", nodeName).Debug(ctx, "Node already completed")

	if processedTmpl.Metrics != nil {
		// Check if this node completed between executions. If it did, emit metrics.
		// We can infer that this node completed during the current operation, emit metrics
		if prevNodeStatus, ok := woc.preExecutionNodeStatuses[node.ID]; ok && !prevNodeStatus.Fulfilled() {
			localScope, realTimeScope := woc.prepareMetricScope(node)
			woc.computeMetrics(ctx, processedTmpl.Metrics.Prometheus, localScope, realTimeScope, false)
		}
	}
	return node
}

func getTimeoutAsDeadline(startedAt *time.Time, timeoutVal string) (*time.Time, error) {
	tmplTimeout, err := wfv1.ParseStringToDuration(timeoutVal)
	if err != nil {
		return nil, fmt.Errorf("invalid timeout format %w", err)
	}
	tmplDeadline := startedAt.Add(tmplTimeout)
	return &tmplDeadline, nil
}

// checkTemplateTimeouts checks if the template has exceeded its Timeout or PendingTimeout.
// It returns the deadline computed from Timeout (enforced via the pod's activeDeadlineSeconds)
// and the deadline computed from PendingTimeout (only set while the node is pending).
// ErrTimeout is returned if the node is pending past either deadline as of now.
// now is supplied by the caller rather than read from time.Now here so the
// caller controls which clock is used: the pure pod builder passes pb.in.now (the
// captured snapshot time) to keep build() deterministic for a given snapshot,
// while the live executeTemplate path passes the current wall-clock.
func (woc *wfOperationCtx) checkTemplateTimeouts(tmpl *wfv1.Template, node *wfv1.NodeStatus, now time.Time) (deadline, pendingDeadline *time.Time, err error) {
	if node == nil {
		return nil, nil, nil
	}

View on GitHub (pinned to 35bff19146)

Solutions

  1. Correct the timeout value in the template to a Go-style duration with units: '30m', '1h', '24h' (express days as 24h).
  2. Run argo lint on the workflow spec before submitting to catch malformed durations early.
  3. If timeout is built from a workflow parameter, dry-run submit (argo submit --dry-run --output json) and verify the resolved timeout string.
  4. Check the wrapped error in the message for the exact parse failure position to find the offending field (template timeout vs activeDeadlineSeconds).

Example fix

timeout: "1d"   # before - invalid
timeout: "24h"  # after
Defensive patterns

Strategy: validation

Validate before calling

import "time"
func validateTimeout(s string) error {
	if s == "" {
		return nil // unset timeout is legal
	}
	_, err := time.ParseDuration(s)
	return err
}

Type guard

func isValidTimeout(s string) bool {
	if s == "" {
		return true
	}
	_, err := time.ParseDuration(s)
	return err == nil
}

Prevention

When it happens

Trigger: A template or step with timeout set to a string that ParseStringToDuration rejects — e.g. '1d', '30', '', or a typo like '5minute' — when getTimeoutAsDeadline is invoked to derive the template deadline from the node's startedAt.

Common situations: Users writing '1d' or '2w' (unsupported by Go duration parsing); timeouts templated from parameters that resolve empty or malformed; copy-pasted cron-style durations ('30m' vs '30min').

Understand the failure class

Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.

Related errors


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