{"record":{"id":"e7db1c6239d94e6e","repo":"argoproj/argo-workflows","slug":"invalid-timeout-format-w","errorCode":null,"errorMessage":"invalid timeout format %w","messagePattern":"invalid timeout format %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"workflow/controller/operator.go","lineNumber":2678,"sourceCode":"\t}\n\n\twoc.log.WithField(\"nodeName\", nodeName).Debug(ctx, \"Node already completed\")\n\n\tif processedTmpl.Metrics != nil {\n\t\t// Check if this node completed between executions. If it did, emit metrics.\n\t\t// We can infer that this node completed during the current operation, emit metrics\n\t\tif prevNodeStatus, ok := woc.preExecutionNodeStatuses[node.ID]; ok && !prevNodeStatus.Fulfilled() {\n\t\t\tlocalScope, realTimeScope := woc.prepareMetricScope(node)\n\t\t\twoc.computeMetrics(ctx, processedTmpl.Metrics.Prometheus, localScope, realTimeScope, false)\n\t\t}\n\t}\n\treturn node\n}\n\nfunc getTimeoutAsDeadline(startedAt *time.Time, timeoutVal string) (*time.Time, error) {\n\ttmplTimeout, err := wfv1.ParseStringToDuration(timeoutVal)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid timeout format %w\", err)\n\t}\n\ttmplDeadline := startedAt.Add(tmplTimeout)\n\treturn &tmplDeadline, nil\n}\n\n// checkTemplateTimeouts checks if the template has exceeded its Timeout or PendingTimeout.\n// It returns the deadline computed from Timeout (enforced via the pod's activeDeadlineSeconds)\n// and the deadline computed from PendingTimeout (only set while the node is pending).\n// ErrTimeout is returned if the node is pending past either deadline as of now.\n// now is supplied by the caller rather than read from time.Now here so the\n// caller controls which clock is used: the pure pod builder passes pb.in.now (the\n// captured snapshot time) to keep build() deterministic for a given snapshot,\n// while the live executeTemplate path passes the current wall-clock.\nfunc (woc *wfOperationCtx) checkTemplateTimeouts(tmpl *wfv1.Template, node *wfv1.NodeStatus, now time.Time) (deadline, pendingDeadline *time.Time, err error) {\n\tif node == nil {\n\t\treturn nil, nil, nil\n\t}\n","sourceCodeStart":2660,"sourceCodeEnd":2696,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/workflow/controller/operator.go#L2660-L2696","documentation":"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.","triggerScenarios":"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.","commonSituations":"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').","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)."],"exampleFix":"timeout: \"1d\"   # before - invalid\ntimeout: \"24h\"  # after","handlingStrategy":"validation","validationCode":"import \"time\"\nfunc validateTimeout(s string) error {\n\tif s == \"\" {\n\t\treturn nil // unset timeout is legal\n\t}\n\t_, err := time.ParseDuration(s)\n\treturn err\n}","typeGuard":"func isValidTimeout(s string) bool {\n\tif s == \"\" {\n\t\treturn true\n\t}\n\t_, err := time.ParseDuration(s)\n\treturn err == nil\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["argo-workflows","duration-parsing","timeout","config-error"],"backgroundTag":"invalid-duration-format","analyzedSha":"35bff19146f5a6ada77468c431f2624bd577e373","analyzedAt":"2026-09-03T19:34:35.908Z","contentChangedAt":"2026-09-03T19:34:35.908Z","schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}