{"record":{"id":"e20f7fd059db54db","repo":"hashicorp/nomad","slug":"http-read-timeout-must-be-0","errorCode":null,"errorMessage":"http_read_timeout must be > 0","messagePattern":"http_read_timeout must be > 0","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/config/artifact.go","lineNumber":172,"sourceCode":"\t\treturn false\n\tcase !pointer.Eq(a.SetEnvironmentVariables, o.SetEnvironmentVariables):\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc (a *ArtifactConfig) Validate() error {\n\tif a == nil {\n\t\treturn fmt.Errorf(\"artifact must not be nil\")\n\t}\n\n\tif a.HTTPReadTimeout == nil {\n\t\treturn fmt.Errorf(\"http_read_timeout must be set\")\n\t}\n\tif v, err := time.ParseDuration(*a.HTTPReadTimeout); err != nil {\n\t\treturn fmt.Errorf(\"http_read_timeout not a valid duration: %w\", err)\n\t} else if v < 0 {\n\t\treturn fmt.Errorf(\"http_read_timeout must be > 0\")\n\t}\n\n\tif a.HTTPMaxSize == nil {\n\t\treturn fmt.Errorf(\"http_max_size must be set\")\n\t}\n\tif v, err := humanize.ParseBytes(*a.HTTPMaxSize); err != nil {\n\t\treturn fmt.Errorf(\"http_max_size not a valid size: %w\", err)\n\t} else if v > math.MaxInt64 {\n\t\treturn fmt.Errorf(\"http_max_size must be < %d but found %d\", int64(math.MaxInt64), v)\n\t}\n\n\tif a.GCSTimeout == nil {\n\t\treturn fmt.Errorf(\"gcs_timeout must be set\")\n\t}\n\tif v, err := time.ParseDuration(*a.GCSTimeout); err != nil {\n\t\treturn fmt.Errorf(\"gcs_timeout not a valid duration: %w\", err)\n\t} else if v < 0 {\n\t\treturn fmt.Errorf(\"gcs_timeout must be > 0\")","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/config/artifact.go#L154-L190","documentation":"Once http_read_timeout parses as a duration, Validate rejects negative values with this message. A negative HTTP read timeout is meaningless for artifact fetching, so the config is treated as invalid. Note the message text says '> 0' while the code checks v < 0; only strictly negative durations trigger it.","triggerScenarios":"Configuring artifact { http_read_timeout = \"-30s\" } or computing a duration programmatically that came out negative (e.g. subtracting timestamps when generating config).","commonSituations":"Hand-edited configs after failed experiments; templating systems that interpolate negative values; accidentally using a negative sentinel to mean 'unlimited'.","solutions":["Set a positive duration, e.g. http_read_timeout = \"30s\".","If a timeout-free behavior is desired, check Nomad docs for the supported 'no timeout' representation instead of using a negative value.","Add a config lint/CI check that artifact durations are > 0.","Fix any code generating durations via time arithmetic that may go negative."],"exampleFix":"// before\nartifact {\n  http_read_timeout = \"-30s\"\n}\n// after\nartifact {\n  http_read_timeout = \"30s\"\n}","handlingStrategy":"validation","validationCode":"if v, err := time.ParseDuration(cfg.Artifact.HTTPReadTimeout); err == nil && v < 0 {\n    return fmt.Errorf(\"http_read_timeout must be positive\")\n}","typeGuard":null,"tryCatchPattern":"if err := cfg.Artifact.Validate(); err != nil {\n    if strings.Contains(err.Error(), \"must be > 0\") {\n        // replace the negative duration with a positive one\n    }\n    return err\n}","preventionTips":["Never configure negative durations; use positive values only.","Check template interpolation for expressions that can yield negatives.","Add config assertions that all duration options are > 0."],"tags":["nomad","config","validation","duration-parsing"],"backgroundTag":"invalid-duration-format","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}