{"record":{"id":"ec51fc6fc8f0722e","repo":"gohugoio/hugo","slug":"invalid-timeout-for-resource-s-w","errorCode":null,"errorMessage":"invalid timeout for resource %s: %w","messagePattern":"invalid timeout for resource (.+?): %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"resources/resource_factories/create/remote.go","lineNumber":215,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse URL for resource %s: %w\", uri, err)\n\t}\n\n\tmethod := \"GET\"\n\tif s, _, ok := hmaps.LookupEqualFold(optionsm, \"method\"); ok {\n\t\tmethod = strings.ToUpper(s.(string))\n\t}\n\tisHeadMethod := method == \"HEAD\"\n\n\toptionsm = maps.Clone(optionsm)\n\n\t// Extract timeout before computing cache keys: it only affects fetch behaviour,\n\t// not the cached content, so it must not influence the cache key.\n\tvar perRequestTimeout time.Duration\n\tif v, k, ok := hmaps.LookupEqualFold(optionsm, \"timeout\"); ok {\n\t\td, err := cast.ToDurationE(v)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid timeout for resource %s: %w\", uri, err)\n\t\t}\n\t\tperRequestTimeout = d\n\t\tdelete(optionsm, k)\n\t}\n\n\tuserKey, optionsKey := remoteResourceKeys(uri, optionsm)\n\n\t// A common pattern is to use the key in the options map as\n\t// a way to control cache eviction,\n\t// so make sure we use any user provided key as the file cache key,\n\t// but the auto generated and more stable key for everything else.\n\tfilecacheKey := userKey\n\n\treturn c.rs.ResourceCache.CacheResourceRemote.GetOrCreate(optionsKey, func(key string) (resource.Resource, error) {\n\t\toptions, err := decodeRemoteOptions(optionsm)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to decode options for resource %s: %w\", uri, err)\n\t\t}","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/resources/resource_factories/create/remote.go#L197-L233","documentation":"Wrapped error from `Client.FromRemote` (remote.go:212-216) when the `timeout` option value cannot be parsed as a duration via `cast.ToDurationE`. The timeout is extracted from the options map before the request is built. Valid forms include Go duration strings (`\"30s\"`), or numeric values that cast can interpret; anything else triggers this.","triggerScenarios":"Calling `resources.GetRemote` with `(dict \"timeout\" <bad>)` where `<bad>` is e.g. a struct, a list, an unparseable string like `\"30 sec\"`, or a bool. `cast.ToDurationE` accepts things like `30000000000` (ns int) or `\"5s\"` but rejects free-form text.","commonSituations":"Typing `timeout = \"30\"` expecting seconds (cast reads it as 30 nanoseconds, not an error, but functionally wrong) vs `timeout = \"30 seconds\"` (parse error); passing a frontmatter value coerced to the wrong type; mixing YAML duration syntax (`timeout: 30s`) with TOML unquoted (`timeout = 30s` triggers parse error in some loaders).","solutions":["Use a Go-style duration string: `(dict \"timeout\" \"30s\")` or `\"500ms\"`.","Quote duration literals in TOML: `timeout = \"30s\"`.","Confirm the frontmatter field holds a string or integer, not a list/map.","Avoid ambiguous forms like `\"30 seconds\"` -- only `s`, `m`, `ms`, `h` suffixes parse."],"exampleFix":"// template -- before\n{{ $r := resources.GetRemote $url (dict \"timeout\" \"30 seconds\") }}\n\n// after\n{{ $r := resources.GetRemote $url (dict \"timeout\" \"30s\") }}","handlingStrategy":"validation","validationCode":"import (\n\t\"fmt\"\n\t\"time\"\n\t\"github.com/spf13/cast\"\n)\nfunc validateDuration(v any) error {\n\tif _, err := cast.ToDurationE(v); err != nil {\n\t\treturn fmt.Errorf(\"invalid duration %v: %w\", v, err)\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use Go duration strings (\"30s\", \"500ms\").","Quote durations in TOML (`timeout = \"30s\"`).","Avoid ambiguous forms like \"30 seconds\"."],"tags":["resources","remote","duration","validation","config"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}