hashicorp/nomad · error
http_read_timeout not a valid duration: %w
Error message
http_read_timeout not a valid duration: %w
What it means
After confirming http_read_timeout is present, Validate parses it with time.ParseDuration and wraps any parse failure with this error (using %w so the underlying ParseDuration error is preserved). It means the configured value is a string but not in Go duration syntax like "30s", "5m", or "1h30m".
Source
Thrown at nomad/structs/config/artifact.go:170
return false
case !helper.SliceSetEq(a.FilesystemIsolationExtraPaths, o.FilesystemIsolationExtraPaths):
return false
case !pointer.Eq(a.SetEnvironmentVariables, o.SetEnvironmentVariables):
return false
}
return true
}
func (a *ArtifactConfig) Validate() error {
if a == nil {
return fmt.Errorf("artifact must not be nil")
}
if a.HTTPReadTimeout == nil {
return fmt.Errorf("http_read_timeout must be set")
}
if v, err := time.ParseDuration(*a.HTTPReadTimeout); err != nil {
return fmt.Errorf("http_read_timeout not a valid duration: %w", err)
} else if v < 0 {
return fmt.Errorf("http_read_timeout must be > 0")
}
if a.HTTPMaxSize == nil {
return fmt.Errorf("http_max_size must be set")
}
if v, err := humanize.ParseBytes(*a.HTTPMaxSize); err != nil {
return fmt.Errorf("http_max_size not a valid size: %w", err)
} else if v > math.MaxInt64 {
return fmt.Errorf("http_max_size must be < %d but found %d", int64(math.MaxInt64), v)
}
if a.GCSTimeout == nil {
return fmt.Errorf("gcs_timeout must be set")
}
if v, err := time.ParseDuration(*a.GCSTimeout); err != nil {
return fmt.Errorf("gcs_timeout not a valid duration: %w", err)View on GitHub (pinned to 482b49bf1a)
Solutions
- Use Go duration syntax with a unit: http_read_timeout = "30s".
- Never set a bare number; ensure the config layer emits a string, not a numeric type.
- Validate the config with 'nomad agent -config ... ' in a CI dry-run before deploying.
- Read the wrapped %w error text from ParseDuration for the exact offending position.
Example fix
// before
artifact {
http_read_timeout = 30
}
// after
artifact {
http_read_timeout = "30s"
} Defensive patterns
Strategy: validation
Validate before calling
if _, err := time.ParseDuration(cfg.Artifact.HTTPReadTimeout); err != nil {
return fmt.Errorf("http_read_timeout must be a Go duration like 30s: %w", err)
} Try / catch
if err := cfg.Artifact.Validate(); err != nil {
if strings.Contains(err.Error(), "not a valid duration") {
// fix the value to Go duration syntax, e.g. "30s"
}
return err
} Prevention
- Always include a unit suffix: s, m, or h.
- Quote duration values in HCL so they remain strings.
- Lint config files with time.ParseDuration before shipping.
- Avoid bare numbers and non-Go unit spellings like 'sec' or 'min'.
When it happens
Trigger: Setting artifact { http_read_timeout = 30 } (a number, coerced to a wrong string), "30", "30 sec", or any value lacking a unit suffix in the Nomad client config.
Common situations: Users writing bare numbers assuming seconds; copy-pasted values with units Go doesn't accept (e.g. "ms" typos like "30sec"); YAML/JSON configs where the value arrived as an int and was stringified as "30".
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
- http_read_timeout must be > 0
- wait config is nil or empty
- missing datacenter for client registration
- default_identity_ttl must be greater than 0
- max_identity_ttl must be greater than 0
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/ecb0b5f47a3e9028.
Report an issue: GitHub.