gohugoio/hugo · error

index not valid

Error message

index %q not valid

What it means

Returned by InvertedIndex.Search when a NamedSlice in opts.NamedSlices has a key that resolves to an empty string via KeyString(). Each named query element must carry a non-empty index key; a blank key means the caller passed an unkeyed slice, which the search cannot route to an index.

Solutions

  1. Ensure every types.KeyValues in NamedSlices has a non-empty Key matching a configured index name.
  2. Validate the key before constructing SearchOpts and skip/log entries with empty keys.
  3. Check the upstream code that builds the named slices to confirm keys are always set.

Example fix

// before: KeyValues built without a key
opts := related.SearchOpts{
  NamedSlices: []types.KeyValues{{Values: []any{"go"}}},
}

// after
opts := related.SearchOpts{
  NamedSlices: []types.KeyValues{{Key: "keywords", Values: []any{"go"}}},
}
Defensive patterns

Strategy: validation

Validate before calling

// Filter out NamedSlices with empty keys before constructing SearchOpts.
func filterEmptyKeys(kv []types.KeyValues) []types.KeyValues {
    out := kv[:0]
    for _, e := range kv {
        if e.KeyString() != "" { out = append(out, e) }
    }
    return out
}

Try / catch

if _, err := idx.Search(ctx, opts); err != nil {
    if strings.Contains(err.Error(), "not valid") { /* empty key -- fix builder */ }
}

Prevention

When it happens

Trigger: Constructing SearchOpts.NamedSlices with a types.KeyValues whose Key is nil/unset (so KeyString() returns the empty string), e.g. passing a positional slice instead of a map-keyed value when building a related query programmatically.

Common situations: Programmatic API misuse where a developer builds types.KeyValues without setting the Key field; a serialization round-trip that drops the key; or a template helper emitting an empty index name.

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/f624fedc422a1b01. Report an issue: GitHub.

Appendix: 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 52c9bd7908)