gohugoio/hugo · error

index %q not valid

Error message

index %q not valid

What it means

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).

Source

Thrown at related/inverted_index.go:393

			for _, fragment := range opts.Fragments {
				keywords = append(keywords, FragmentKeyword(fragment))
			}
			if opts.Document != nil {
				if fp, ok := opts.Document.(FragmentProvider); ok {
					for _, fragment := range fp.Fragments(ctx).Identifiers {
						keywords = append(keywords, FragmentKeyword(fragment))
					}
				}
			}

		}
		queryElements = append(queryElements, newQueryElement(cfg.Name, keywords...))
	}
	for _, slice := range opts.NamedSlices {
		var keywords []Keyword
		key := slice.KeyString()
		if key == "" {
			return nil, fmt.Errorf("index %q not valid", slice.Key)
		}
		conf, found := idx.getIndexCfg(key)
		if !found {
			return nil, fmt.Errorf("index %q not found", key)
		}

		for _, val := range slice.Values {
			k, err := conf.ToKeywords(val)
			if err != nil {
				return nil, err
			}
			keywords = append(keywords, k...)
		}
		queryElements = append(queryElements, newQueryElement(conf.Name, keywords...))
	}

	if opts.Document != nil {
		return idx.searchDate(ctx, opts.Document, opts.Document.PublishDate(), queryElements...)

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Ensure the first argument to `keyVals` in the template is a non-empty string naming a configured related index.
  2. Guard the template: skip the Related call when the variable holding the index name is empty (`{{ with $name }}...{{ end }}`).

Example fix

// before
{{ $related := site.RegularPages.Related (dict "document" . "namedSlices" (slice (keyVals $name "a"))) }}
// after
{{ with $name }}{{ $related := site.RegularPages.Related (dict "document" $ "namedSlices" (slice (keyVals . "a"))) }}{{ end }}
Defensive patterns

Strategy: validation

Validate before calling

# An index used for search must be enabled and applicable
[[related.indices]]
  name = "tags"
  weight = 80
  # ensure weight > 0; weight 0 disables the index

Type guard

func indexUsable(ic related.IndexConfig) bool {
    return ic.Weight > 0
}

Try / catch

docs, err := idx.SearchDoc(doc, indices...)
if err != nil {
    // "index not valid" => index exists but is disabled/unusable for this query
    return fmt.Errorf("related index misconfigured: %w", err)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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`.

Related errors


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/f624fedc422a1b01.json. Report an issue: GitHub ↗.