Prometheus Error Guide: 'not a valid duration string' — Fix Rule Config
Fix Prometheus 'not a valid duration string' errors in rule and config files: correct missing units, bad range vectors, and durations so config reload succeeds.
- #prometheus
- #monitoring
- #troubleshooting
- #errors
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
Prometheus rejects a config or rule file with this error whenever a duration value is missing its unit or otherwise malformed:
not a valid duration string: "5"
It surfaces at startup, on promtool check, and during a live /-/reload, often wrapped with the file and line:
loading rule files: rule.yml: group "api" rule 3: field 'for': not a valid duration string: "5m30"
Prometheus durations require an integer with a unit suffix (s, m, h, d, w, y) — 5 is invalid, 5m is valid. Until the value is fixed, the reload fails and Prometheus keeps running the last-good config (or refuses to start if it’s the initial load), so your intended rule and scrape changes silently do not take effect.
Symptoms
promtool check config/check rulesfails withnot a valid duration string.- A
/-/reloadreturns400and the log names the offending field (for,scrape_interval,evaluation_interval, etc.). - New rules or scrape timing changes don’t take effect — the old config is still live.
- Prometheus fails to start after an edit, exiting immediately with the parse error.
- The bad value is a bare number (
30) or a malformed compound (1m30,5 m).
Common Root Causes
- Missing unit —
for: 5instead offor: 5m. - Malformed compound duration —
1m30instead of1m30s, or a stray space like5 m. - A range vector in PromQL without a unit —
rate(x[5])instead ofrate(x[5m]). - Templated/interpolated value — a Helm or CI variable rendered a number without a unit suffix.
- Wrong field type — putting a duration where a count is expected, or vice versa, so parsing chokes.
- Copy-paste from another system (e.g. milliseconds
500msis valid, but0.5is not).
Diagnostic Workflow
Validate before reloading — promtool pinpoints the file, group, and field:
promtool check config /etc/prometheus/prometheus.yml
promtool check rules /etc/prometheus/rules/*.yml
Search for bare-number durations across the config and rules:
grep -rnE '(for|scrape_interval|scrape_timeout|evaluation_interval|interval):[[:space:]]*"?[0-9]+"?[[:space:]]*$' \
/etc/prometheus/
Look for range vectors missing a unit inside expressions:
grep -rnE '\[[0-9]+\]' /etc/prometheus/rules/
A correct rule uses unit-suffixed durations everywhere:
groups:
- name: api
interval: 30s
rules:
- alert: HighErrorRate
expr: rate(http_requests_total{code=~"5.."}[5m]) > 1
for: 5m # NOT "5"
labels: { severity: critical }
Reload only after promtool passes, and confirm it took:
curl -sS -X POST http://localhost:9090/-/reload -w '%{http_code}\n'
Example Root Cause Analysis
A CI pipeline rendered alerting rules from a Helm template where for was set from a values field alertFor: 5, intended as “5 minutes.” The template emitted for: 5, and the next /-/reload returned 400 with field 'for': not a valid duration string: "5". Because the reload failed, the new rules never loaded — the on-call team thought a new alert was live when it wasn’t.
promtool check rules in CI would have caught it pre-merge. The fix was to store the value as 5m (or append the unit in the template: {{ .Values.alertFor }}m) and add a promtool check gate to the pipeline so a unitless duration can never reach production again.
Prevention Best Practices
- Run
promtool check configandpromtool check rulesin CI on every change so bad durations fail the build, not the reload. - Store durations with explicit units in values/config templates, or append the unit in the template itself.
- Prefer
/-/reload(with--web.enable-lifecycle) only after a successfulpromtoolcheck, and verify the reload HTTP status. - Standardize on unit suffixes in review checklists; reject bare numbers for any time field.
- Watch
prometheus_config_last_reload_successful == 0and alert on it so a silently-rejected reload is visible.
Quick Command Reference
# Validate before reloading
promtool check config /etc/prometheus/prometheus.yml
promtool check rules /etc/prometheus/rules/*.yml
# Find bare-number durations and unitless range vectors
grep -rnE '(for|interval):[[:space:]]*"?[0-9]+"?$' /etc/prometheus/
grep -rnE '\[[0-9]+\]' /etc/prometheus/rules/
# Reload and confirm
curl -sS -X POST http://localhost:9090/-/reload -w '%{http_code}\n'
prometheus_config_last_reload_successful
Conclusion
not a valid duration string means a time value is missing its unit or malformed — Prometheus durations need suffixes like s, m, h. Because a failed reload leaves the old config live, the real danger is silently un-applied changes. Gate every config and rule change on promtool check in CI and alert on prometheus_config_last_reload_successful so these errors never reach — or quietly linger in — production.
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.