{"id":"54625cf05bbad9b6","repo":"gohugoio/hugo","slug":"cannot-convert-v-to-time-duration","errorCode":null,"errorMessage":"cannot convert %v to time.Duration","messagePattern":"cannot convert (.+?) to time\\.Duration","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/types/convert.go","lineNumber":40,"sourceCode":"\n\t\"github.com/spf13/cast\"\n)\n\n// ToDuration converts v to time.Duration.\n// See ToDurationE if you need to handle errors.\nfunc ToDuration(v any) time.Duration {\n\td, _ := ToDurationE(v)\n\treturn d\n}\n\n// ToDurationE converts v to time.Duration.\nfunc ToDurationE(v any) (time.Duration, error) {\n\tif n := cast.ToInt(v); n > 0 {\n\t\treturn time.Duration(n) * time.Millisecond, nil\n\t}\n\td, err := time.ParseDuration(cast.ToString(v))\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"cannot convert %v to time.Duration\", v)\n\t}\n\treturn d, nil\n}\n\n// ToStringSlicePreserveString is the same as ToStringSlicePreserveStringE,\n// but it never fails.\nfunc ToStringSlicePreserveString(v any) []string {\n\tvv, _ := ToStringSlicePreserveStringE(v)\n\treturn vv\n}\n\n// ToStringSlicePreserveStringE converts v to a string slice.\n// If v is a string, it will be wrapped in a string slice.\nfunc ToStringSlicePreserveStringE(v any) ([]string, error) {\n\tif v == nil {\n\t\treturn nil, nil\n\t}\n\tif sds, ok := v.(string); ok {","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/common/types/convert.go#L22-L58","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before (hugo.toml)\n[caches.getjson]\nmaxAge = \"1d\"\n\n# after\n[caches.getjson]\nmaxAge = \"24h\"","handlingStrategy":"type-guard","validationCode":"switch v.(type) {\ncase time.Duration, int, int32, int64, string:\n    // convertible\ndefault:\n    return fmt.Errorf(\"unsupported duration type %T\", v)\n}","typeGuard":"func toDuration(v any) (time.Duration, bool) {\n    switch t := v.(type) {\n    case time.Duration:\n        return t, true\n    case int, int32, int64:\n        return time.Duration(cast.ToInt64(t)) * time.Millisecond, true\n    case string:\n        d, err := time.ParseDuration(t)\n        return d, err == nil\n    }\n    return 0, false\n}","tryCatchPattern":"if err != nil {\n    // fix the config value format (e.g. \"30s\") rather than retrying\n}","preventionTips":["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"],"tags":["hugo","config","duration","type-conversion"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}