{"id":"20db514a388138ba","repo":"gohugoio/hugo","slug":"no-key-set-in-resource","errorCode":null,"errorMessage":"no Key set in Resource","messagePattern":"no Key set in Resource","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/openapi/openapi3/openapi3.go","lineNumber":79,"sourceCode":"func (o *OpenAPIDocument) GetIdentityGroup() identity.Identity {\n\treturn o.identityGroup\n}\n\ntype unmarshalOptions struct {\n\t// Options passed to resources.GetRemote when resolving remote $ref.\n\tGetRemote map[string]any\n}\n\n// Unmarshal unmarshals the given resource into an OpenAPI 3 document.\nfunc (ns *Namespace) Unmarshal(ctx context.Context, args ...any) (*OpenAPIDocument, error) {\n\tif len(args) < 1 || len(args) > 2 {\n\t\treturn nil, errors.New(\"must provide a Resource and optionally an options map\")\n\t}\n\n\tr := args[0].(resource.UnmarshableResource)\n\tkey := r.Key()\n\tif key == \"\" {\n\t\treturn nil, errors.New(\"no Key set in Resource\")\n\t}\n\n\tvar opts unmarshalOptions\n\tif len(args) > 1 {\n\t\toptsm, err := hmaps.ToStringMapE(args[1])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := mapstructure.WeakDecode(optsm, &opts); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tkey += \"_\" + hashing.HashString(optsm)\n\t}\n\n\tv, err := ns.cache.GetOrCreate(key, func(string) (*OpenAPIDocument, error) {\n\t\tf := metadecoders.FormatFromStrings(r.MediaType().Suffixes()...)\n\t\tif f == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"MIME %q not supported\", r.MediaType())","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/tpl/openapi/openapi3/openapi3.go#L61-L97","documentation":"After the arity check, `openapi3.Unmarshal` (tpl/openapi/openapi3/openapi3.go:79) calls `Key()` on the passed Resource to build its cache key. A Resource with an empty Key cannot be cached or identified, so Hugo rejects it. This typically means the value passed is not a normal file-backed asset resource.","triggerScenarios":"Passing a Resource whose `Key()` returns \"\" — e.g. a hand-constructed or exotic resource type rather than one obtained from `resources.Get`, `resources.GetRemote`, or `resources.FromString`.","commonSituations":"Passing the result of a failed/odd resource pipeline, custom modules producing resources without keys, or (in older Hugo versions) certain remote/derived resources that lacked keys. Rare in practice; usually indicates the wrong object is being passed.","solutions":["Obtain the spec via the standard resource functions: `{{ $r := resources.Get \"api/openapi.yaml\" }}` and pass `$r`.","Verify the resource exists and is non-nil before calling Unmarshal: `{{ with resources.Get \"api/openapi.yaml\" }}{{ $api := openapi3.Unmarshal . }}{{ end }}`.","Upgrade Hugo if a known resource type is missing its Key in your version."],"exampleFix":"<!-- before: passing an ad-hoc value -->\n{{ $api := openapi3.Unmarshal $someObject }}\n<!-- after -->\n{{ with resources.Get \"api/openapi.yaml\" }}\n  {{ $api := openapi3.Unmarshal . }}\n{{ end }}","handlingStrategy":"validation","validationCode":"{{ $spec := resources.Get \"api/openapi.yaml\" }}\n{{ if and $spec $spec.Key }}\n  {{ $doc := openapi3.Unmarshal $spec }}\n{{ end }}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use resources obtained from Hugo's resource pipeline (resources.Get, GetRemote, page resources) — these carry a Key","Avoid hand-constructed or wrapped objects that mimic a Resource without a Key","If a transform chain drops identity, unmarshal the original resource instead of the derived one"],"tags":["hugo","templates","openapi","resources"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}