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
- Correct the timeout value in the template to a Go-style duration with units: '30m', '1h', '24h' (express days as 24h).
- Run argo lint on the workflow spec before submitting to catch malformed durations early.
- If timeout is built from a workflow parameter, dry-run submit (argo submit --dry-run --output json) and verify the resolved timeout string.
- 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
- Write timeouts in Go duration syntax: 30m, 1h, 24h — avoid '1d'/'1w'.
- Lint all workflow specs with argo lint in CI before submission.
- When injecting timeout via parameters, validate the resolved string during dry-run.
- Keep timeout literals in a shared, tested constant set rather than free-form strings.
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.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- invalid maxAge: %w
- supervisor presumed dead: status marker never appeared withi
- single branch mode without a branch specified
- duplicate synchronization item found
- CodeBadRequest
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/e7db1c6239d94e6e.
Report an issue: GitHub.