{"id":"5371f4c10f41a2a1","repo":"gohugoio/hugo","slug":"invalid-type-t-in-related-search","errorCode":null,"errorMessage":"invalid type %T in related search","messagePattern":"invalid type %T in related search","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"resources/page/pages_related.go","lineNumber":129,"sourceCode":"\t}\n\n\treturn p.search(ctx, opts)\n}\n\nfunc (p Pages) search(ctx context.Context, opts related.SearchOpts) (Pages, error) {\n\treturn p.withInvertedIndex(ctx, func(idx *related.InvertedIndex) ([]related.Document, error) {\n\t\treturn idx.Search(ctx, opts)\n\t})\n}\n\nfunc (p Pages) withInvertedIndex(ctx context.Context, search func(idx *related.InvertedIndex) ([]related.Document, error)) (Pages, error) {\n\tif len(p) == 0 {\n\t\treturn nil, nil\n\t}\n\n\td, ok := p[0].(RelatedDocsHandlerProvider)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"invalid type %T in related search\", p[0])\n\t}\n\n\tcache := d.GetInternalRelatedDocsHandler()\n\n\tsearchIndex, err := cache.getOrCreateIndex(ctx, p)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult, err := search(searchIndex)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(result) > 0 {\n\t\tmp := make(Pages, len(result))\n\t\tfor i, match := range result {\n\t\t\tmp[i] = match.(Page)","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/resources/page/pages_related.go#L111-L147","documentation":"All related-content searches funnel through Pages.withInvertedIndex, which type-asserts the first page in the collection to RelatedDocsHandlerProvider to obtain the site's related-docs cache and inverted index. If that assertion fails — the collection's elements aren't real page objects backed by the site — the search cannot proceed and this error names the actual type found.","triggerScenarios":"Calling `.Related`, `.RelatedIndices`, or `.RelatedTo` on a Pages collection whose first element is not a full site-backed Page — e.g. a collection hand-built in a template from non-page values, or synthetic/wrapped page types (custom code, tests) that don't implement RelatedDocsHandlerProvider.","commonSituations":"Building a slice with `slice`/`append` in templates that mixes pages with other values, template constructs that yield page-like adapters rather than concrete pages, or (for Hugo module/tool developers) passing mock pages into the related API.","solutions":["Run Related on a real page collection such as `site.RegularPages` or `.Pages` instead of a hand-assembled slice.","If you filtered/assembled the collection yourself, make sure every element originates from site pages (e.g. use `where` on site.Pages rather than building a new slice from arbitrary values).","In custom Go code or tests, use pages created by the Hugo site (hugolib.Test) so they implement the internal RelatedDocsHandlerProvider interface."],"exampleFix":"<!-- before: hand-built collection of non-page values -->\n{{ $coll := slice .Title .Section }}\n{{ $related := $coll.Related . }}\n<!-- after: search a real page collection -->\n{{ $related := site.RegularPages.Related . }}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func validRelatedKeyVal(v any) bool {\n    switch v.(type) {\n    case string, []string, time.Time:\n        return true\n    default:\n        return false\n    }\n}","tryCatchPattern":null,"preventionTips":["In related searches, index values must be strings, string slices, or dates — convert numbers with `string`/`printf` first","Ensure front matter fields used as related indices have consistent types across all pages","Declare related indices explicitly in site config so indexed params are known types","Add a test site build covering pages with edge-case front matter types"],"tags":["hugo","templates","related-content","type-assertion"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}