gohugoio/hugo · error
cannot convert %v to time.Duration
Error message
cannot convert %v to time.Duration
What it means
`types.ToDurationE` converts an arbitrary value to `time.Duration`: positive integers are treated as milliseconds; anything else is stringified and parsed with `time.ParseDuration`. If the string form doesn't parse (e.g. missing unit, non-numeric text, or a zero/negative int falling through to string parsing), this error is returned with the original value.
Source
Thrown at common/types/convert.go:40
"github.com/spf13/cast"
)
// ToDuration converts v to time.Duration.
// See ToDurationE if you need to handle errors.
func ToDuration(v any) time.Duration {
d, _ := ToDurationE(v)
return d
}
// ToDurationE converts v to time.Duration.
func ToDurationE(v any) (time.Duration, error) {
if n := cast.ToInt(v); n > 0 {
return time.Duration(n) * time.Millisecond, nil
}
d, err := time.ParseDuration(cast.ToString(v))
if err != nil {
return 0, fmt.Errorf("cannot convert %v to time.Duration", v)
}
return d, nil
}
// ToStringSlicePreserveString is the same as ToStringSlicePreserveStringE,
// but it never fails.
func ToStringSlicePreserveString(v any) []string {
vv, _ := ToStringSlicePreserveStringE(v)
return vv
}
// ToStringSlicePreserveStringE converts v to a string slice.
// If v is a string, it will be wrapped in a string slice.
func ToStringSlicePreserveStringE(v any) ([]string, error) {
if v == nil {
return nil, nil
}
if sds, ok := v.(string); ok {View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Add a valid Go duration unit to the value: use forms like "300ms", "10s", "5m", "2h".
- Replace day-based values ("7d") with hours ("168h").
- If you meant milliseconds, pass a positive integer instead of a string.
- Find the offending config key by searching for the printed value in your config files.
Example fix
# before (hugo.toml) [caches.getjson] maxAge = "1d" # after [caches.getjson] maxAge = "24h"
Defensive patterns
Strategy: type-guard
Validate before calling
switch v.(type) {
case time.Duration, int, int32, int64, string:
// convertible
default:
return fmt.Errorf("unsupported duration type %T", v)
} Type guard
func toDuration(v any) (time.Duration, bool) {
switch t := v.(type) {
case time.Duration:
return t, true
case int, int32, int64:
return time.Duration(cast.ToInt64(t)) * time.Millisecond, true
case string:
d, err := time.ParseDuration(t)
return d, err == nil
}
return 0, false
} Try / catch
if err != nil {
// fix the config value format (e.g. "30s") rather than retrying
} Prevention
- Express durations in config as Go duration strings ("500ms", "30s", "5m")
- Don't pass maps, slices, or floats where a duration is expected
- Remember bare integers are interpreted as milliseconds — prefer explicit unit strings
When it happens
Trigger: Config values or template arguments expected to be durations — e.g. cache TTLs (`[caches.getjson] maxAge = ...`), `timeout` settings, or module config — set to strings without a unit ("30"), unsupported units ("1d"), or non-duration text.
Common situations: Writing `maxAge = "10"` instead of `"10s"`; using "1d" (Go's ParseDuration has no day unit — use "24h"); passing `-1` as a string in a context that string-parses it; YAML turning a value into an unexpected type.
Related errors
- language %q not found
- unsupported format: %q
- failed to create workingDir: %w
- conf must be set
- errConfigNotSet
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/54625cf05bbad9b6.json.
Report an issue: GitHub ↗.