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

  1. Add a valid Go duration unit to the value: use forms like "300ms", "10s", "5m", "2h".
  2. Replace day-based values ("7d") with hours ("168h").
  3. If you meant milliseconds, pass a positive integer instead of a string.
  4. 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

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


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/54625cf05bbad9b6.json. Report an issue: GitHub ↗.