{"record":{"id":"8195a128867f34c1","repo":"argoproj/argo-workflows","slug":"duration-has-to-be-positive-current-duration-v","errorCode":null,"errorMessage":"duration has to be positive, current duration: %v ","messagePattern":"duration has to be positive, current duration: (.+?) ","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/apis/workflow/v1alpha1/container_set_template_types.go","lineNumber":47,"sourceCode":"\nfunc (in *ContainerSetTemplate) GetRetryStrategy() (wait.Backoff, error) {\n\tif in == nil || in.RetryStrategy == nil || in.RetryStrategy.Retries == nil {\n\t\treturn wait.Backoff{Steps: 1}, nil\n\t}\n\n\tbackoff := wait.Backoff{Steps: in.RetryStrategy.Retries.IntValue()}\n\n\tif in.RetryStrategy.Duration == \"\" {\n\t\treturn backoff, nil\n\t}\n\n\tbaseDuration, err := time.ParseDuration(in.RetryStrategy.Duration)\n\tif err != nil {\n\t\treturn wait.Backoff{}, err\n\t}\n\n\tif baseDuration < time.Duration(0) {\n\t\treturn wait.Backoff{}, fmt.Errorf(\"duration has to be positive, current duration: %v \", baseDuration)\n\t}\n\n\tbackoff.Duration = baseDuration\n\treturn backoff, nil\n}\n\nfunc (in *ContainerSetTemplate) GetContainers() []corev1.Container {\n\tvar ctrs []corev1.Container\n\tfor _, t := range in.GetGraph() {\n\t\tc := t.Container\n\t\tc.VolumeMounts = append(c.VolumeMounts, in.VolumeMounts...)\n\t\tctrs = append(ctrs, c)\n\t}\n\treturn ctrs\n}\n\nfunc (in *ContainerSetTemplate) HasContainerNamed(n string) bool {\n\tfor _, c := range in.GetContainers() {","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/pkg/apis/workflow/v1alpha1/container_set_template_types.go#L29-L65","documentation":"ContainerSetTemplate.GetRetryStrategy parses the RetryStrategy.Duration string into a time.Duration and rejects negative values, because backoff durations used for retrying failed containers must be >= 0. A negative duration cannot produce a valid wait.Backoff.","triggerScenarios":"Setting retryStrategy.duration in a ContainerSetTemplate to a string that time.ParseDuration resolves to a negative value, e.g. \"-5s\", then calling GetRetryStrategy (directly or via validation of the ContainerSet).","commonSituations":"Copy-pasted retry config with a stray minus sign; templating/variable substitution producing \"-{{delay}}\"; confusing required-positivity with zero-allowed (0 is accepted here, negative is not).","solutions":["Set retryStrategy.duration to a non-negative Go duration string, e.g. \"30s\".","Remove the leading '-' from the duration value in the manifest.","Validate the duration with time.ParseDuration before submitting the workflow."],"exampleFix":"// before\nretryStrategy:\n  duration: -5s\n// after\nretryStrategy:\n  duration: 5s","handlingStrategy":"validation","validationCode":"if d, err := time.ParseDuration(rs.Duration); err != nil || d < 0 {\n    return fmt.Errorf(\"invalid retry duration %q\", rs.Duration)\n}","typeGuard":null,"tryCatchPattern":"backoff, err := cs.GetRetryStrategy()\nif err != nil {\n    if strings.Contains(err.Error(), \"duration has to be positive\") {\n        return fmt.Errorf(\"fix retryStrategy.duration: %w\", err)\n    }\n    return err\n}","preventionTips":["Never emit duration strings from templates with a possible leading '-'.","Unit-test retry configs with time.ParseDuration before submit.","Remember 0 is allowed, negative is not — clamp negative values to 0 or a positive default."],"tags":["go","validation","retry-strategy","container-set"],"backgroundTag":"invalid-duration-value","analyzedSha":"35bff19146f5a6ada77468c431f2624bd577e373","analyzedAt":"2026-09-03T19:34:35.908Z","contentChangedAt":"2026-09-03T19:34:35.908Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}