Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Prometheus & Monitoring By James Joyner IV · · 8 min read

Prometheus Error Guide: 'not a valid duration string' — Fix Rule Config

Quick answer

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
Free toolkit

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 rules fails with not a valid duration string.
  • A /-/reload returns 400 and 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 unitfor: 5 instead of for: 5m.
  • Malformed compound duration1m30 instead of 1m30s, or a stray space like 5 m.
  • A range vector in PromQL without a unitrate(x[5]) instead of rate(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 500ms is valid, but 0.5 is 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 config and promtool check rules in 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 successful promtool check, 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 == 0 and 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.

Free download · 368-page PDF

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.