ErrLookupBackground articles › "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts

"invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts

"invalid duration", "failed to parse ... as time.Duration", and "invalid timeout format" errors appear when a library receives a duration string — a timeout, interval, TTL, retention window, or schedule — in a format its parser does not accept, most often because a unit is missing ("30" instead of "30s"), the unit is unsupported or misnamed ("1d" in Go code, "30min" instead of "30m"), or the value mixes in syntax from another ecosystem. This article explains why duration parsing fails so often, how each library's accepted grammar differs, and how to write duration values that survive validation.

Distilled from 102 documented records across 32 repositories.

Background

This family lives at a thin but strict boundary: almost every library accepts durations as human-written strings, then immediately converts them to a native numeric type before use — Go's time.ParseDuration (jaeger, fabric, weaviate, dagger, argo-workflows, go-micro, nomad, VictoriaMetrics, k6, siyuan, mcp-toolbox), Rust character-walkers building integer spans (CodeWhale's parse_duration_secs, mise's jiff-based parser), regex-validated settings mungers (puppet's DurationSetting, mastra's parseDuration, oh-my-pi's tmpfilesTtlSeconds), and hand-rolled suffix checkers (deepagents requiring 'm' or 'h', hadoop's lowercase s/m/h/d, litellm's '1h'/'24h'/'7d'/'30d' hint). The parse happens at exactly the moment the value is needed — config load, agent start, function definition, template execution — so failure is always fail-fast, and the raw string lands in the error message alongside a parse cause.

From the caller's side the failure looks absurdly narrow: "500" is rejected because the parser cannot guess whether you meant seconds or milliseconds, "1d" fails in every Go ParseDuration code path because Go has no 'd' unit, and "30min" fails wherever the grammar is a single unit letter or token. The error fires at surprising depths — a channel config block in Fabric (where bad consensus metadata breaks every orderer on the channel), a nomad plugin config, an env var like RUNTIME_OVERRIDES_LOAD_INTERVAL or K6_WEB_DASHBOARD_PERIOD, or a single workflow template field — so the string may come from YAML, HCL, puppet.conf, a cron-ish schedule, or a CLI flag, and the offending value is often templated or interpolated, which is where stray whitespace, empty strings, and raw numbers sneak in.

Most libraries layer additional semantic checks on top of syntax, which widens the family: litellm also rejects non-positive durations ('0h', '-30d') and date-arithmetic overflows; nomad requires start_timeout to be positive; mise rejects negative spans outright; puppet rejects decimals, negatives, and compound strings like '1h30m'; deepagents requires a plain decimal integer before the suffix; CodeWhale rejects components at or above 2^63 and has no millisecond support. Accepted grammars disagree sharply — Go is ns/us/ms/s/m/h with compounds allowed and no 'd'; hadoop allows 'd' but not 'w'; puppet allows 'y' and 'd' but exactly one unit; mastra allows ms/s/m/h/d/w with decimals; k6 and weaviate are pure Go. A value valid in one system is routinely invalid in the next, which is the core reason this family is so well-populated.

Common causes

What usually fixes it

Go deeper

Documented occurrences

…and 82 more across the corpus — use search.

Honest provenance: generated on 2026-09-05 from AI-assisted analysis of the linked records. See how records are made.