{"id":"f624fedc422a1b01","repo":"gohugoio/hugo","slug":"index-q-not-valid","errorCode":null,"errorMessage":"index %q not valid","messagePattern":"index %q not valid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"related/inverted_index.go","lineNumber":393,"sourceCode":"\t\t\tfor _, fragment := range opts.Fragments {\n\t\t\t\tkeywords = append(keywords, FragmentKeyword(fragment))\n\t\t\t}\n\t\t\tif opts.Document != nil {\n\t\t\t\tif fp, ok := opts.Document.(FragmentProvider); ok {\n\t\t\t\t\tfor _, fragment := range fp.Fragments(ctx).Identifiers {\n\t\t\t\t\t\tkeywords = append(keywords, FragmentKeyword(fragment))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t\tqueryElements = append(queryElements, newQueryElement(cfg.Name, keywords...))\n\t}\n\tfor _, slice := range opts.NamedSlices {\n\t\tvar keywords []Keyword\n\t\tkey := slice.KeyString()\n\t\tif key == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"index %q not valid\", slice.Key)\n\t\t}\n\t\tconf, found := idx.getIndexCfg(key)\n\t\tif !found {\n\t\t\treturn nil, fmt.Errorf(\"index %q not found\", key)\n\t\t}\n\n\t\tfor _, val := range slice.Values {\n\t\t\tk, err := conf.ToKeywords(val)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tkeywords = append(keywords, k...)\n\t\t}\n\t\tqueryElements = append(queryElements, newQueryElement(conf.Name, keywords...))\n\t}\n\n\tif opts.Document != nil {\n\t\treturn idx.searchDate(ctx, opts.Document, opts.Document.PublishDate(), queryElements...)","sourceCodeStart":375,"sourceCodeEnd":411,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/related/inverted_index.go#L375-L411","documentation":"When a related-content query is made with named key/value slices (the `keyvals`-style arguments), each slice's key must stringify to a non-empty index name via KeyString(). An empty result means the key wasn't a usable string, so Hugo rejects the query rather than searching an unnamed index (related/inverted_index.go:389-394).","triggerScenarios":"Passing a NamedSlice whose Key is not a string (or stringifies to \"\") to InvertedIndex.Search — in templates, calling `.Related` with a `keyvals` entry built from `keyVals` where the key argument is empty or a non-string value.","commonSituations":"Template code computing the index name from a variable that is empty for some pages (`keyVals $missingParam ...`), or passing a non-string object as the key in `keyVals`.","solutions":["Ensure the first argument to `keyVals` in the template is a non-empty string naming a configured related index.","Guard the template: skip the Related call when the variable holding the index name is empty (`{{ with $name }}...{{ end }}`)."],"exampleFix":"// before\n{{ $related := site.RegularPages.Related (dict \"document\" . \"namedSlices\" (slice (keyVals $name \"a\"))) }}\n// after\n{{ with $name }}{{ $related := site.RegularPages.Related (dict \"document\" $ \"namedSlices\" (slice (keyVals . \"a\"))) }}{{ end }}","handlingStrategy":"validation","validationCode":"# An index used for search must be enabled and applicable\n[[related.indices]]\n  name = \"tags\"\n  weight = 80\n  # ensure weight > 0; weight 0 disables the index","typeGuard":"func indexUsable(ic related.IndexConfig) bool {\n    return ic.Weight > 0\n}","tryCatchPattern":"docs, err := idx.SearchDoc(doc, indices...)\nif err != nil {\n    // \"index not valid\" => index exists but is disabled/unusable for this query\n    return fmt.Errorf(\"related index misconfigured: %w\", err)\n}","preventionTips":["Don't query indices whose weight is 0 (disabled)","Match the query type to the index type (e.g. don't do fragment/text queries against a basic keyword index)","After editing [related] config, exercise a page with `.Related` in a test build to catch invalid-index errors early"],"tags":["related-content","templates","validation"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}