{"record":{"id":"f9992b46af268bfd","repo":"gohugoio/hugo","slug":"no-key-set-in-resource-f9992b","errorCode":null,"errorMessage":"no Key set in Resource","messagePattern":"no Key set in Resource","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/transform/unmarshal.go","lineNumber":67,"sourceCode":"\t\tm, ok := args[0].(map[string]any)\n\t\tif !ok {\n\t\t\treturn nil, errors.New(\"first argument must be a map\")\n\t\t}\n\n\t\tvar err error\n\n\t\tdata = args[1]\n\t\tdecoder, err = decodeDecoder(m)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to decode options: %w\", err)\n\t\t}\n\t}\n\n\tif r, ok := data.(resource.UnmarshableResource); ok {\n\t\tkey := r.Key()\n\n\t\tif key == \"\" {\n\t\t\treturn nil, errors.New(\"no Key set in Resource\")\n\t\t}\n\n\t\tif decoder != metadecoders.Default {\n\t\t\tkey += decoder.OptionsKey()\n\t\t}\n\n\t\tv, err := ns.cacheUnmarshal.GetOrCreate(key, func(string) (*resources.StaleValue[any], error) {\n\t\t\tvar f metadecoders.Format\n\t\t\tif decoder.Format != \"\" {\n\t\t\t\tf = metadecoders.FormatFromString(decoder.Format)\n\t\t\t\tif f == \"\" {\n\t\t\t\t\treturn nil, fmt.Errorf(\"format %q not supported\", decoder.Format)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tf = metadecoders.FormatFromStrings(r.MediaType().Suffixes()...)\n\t\t\t\tif f == \"\" {\n\t\t\t\t\treturn nil, fmt.Errorf(\"MIME %q not supported\", r.MediaType())\n\t\t\t\t}","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/tpl/transform/unmarshal.go#L49-L85","documentation":"Thrown by transform.Unmarshal when the data argument is a Resource (implements UnmarshableResource) but its Key() returns an empty string (tpl/transform/unmarshal.go:64-67). The Key is used for caching the unmarshalled result; an empty key would defeat caching and is treated as a misconfiguration.","triggerScenarios":"Calling {{ transform.Unmarshal .Resource }} (or with options) where .Resource is a dynamically created resource (e.g. from resources.FromString) that has no Key/Permalink set.","commonSituations":"Using resources.FromString or resources.Concat without assigning a name/key; passing a remote resource fetched without a key; resources created in templates that bypass the resource system's key assignment.","solutions":["Ensure the resource has a Key by giving it a path: use resources.GetRemote with a key, or name the resource so a key is derived.","If the resource is built via resources.FromString, materialize it through a pipeline step that assigns a key.","Alternatively, read the resource content into a string and Unmarshal the string instead of the Resource."],"exampleFix":"// before\n{{ $r := resources.FromString \"tmp\" .Raw }}\n{{ transform.Unmarshal $r }}\n// after\n{{ transform.Unmarshal $r.Content }}","handlingStrategy":"validation","validationCode":"{{/* Prefer Unmarshalling a string, or ensure the Resource has a Key */}}\n{{ transform.Unmarshal $r.Content }}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Avoid passing resources created without a key (e.g. resources.FromString) directly to Unmarshal.","Give remote/string resources a name so a Key is derived.","Unmarshal the resource's content string instead when a key cannot be set."],"tags":["template-function","transform","unmarshal","resources","caching","hugo"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}