hashicorp/consul · error
The Indexer must also implement one of the SingleIndexer or
Error message
The Indexer must also implement one of the SingleIndexer or MultiIndexer interfaces
What it means
index.New normalizes its Indexer argument into a MultiIndexer via a type switch: it must implement either SingleIndexer (FromArgs + FromObject) or MultiIndexer (FromArgs + FromObjects). A value implementing neither hits the default case and panics — this is a fail-fast replacement for the runtime method-not-found failure that would otherwise occur the first time the cache tried to use the index.
Source
Thrown at internal/controller/cache/index/index.go:32
indexer MultiIndexer
}
func New(name string, i Indexer, opts ...IndexOption) *Index {
if name == "" {
panic("all indexers must have a non-empty name")
}
if i == nil {
panic("no indexer was supplied when creating a new cache Index")
}
var multiIndexer MultiIndexer
switch v := i.(type) {
case SingleIndexer:
multiIndexer = singleIndexWrapper{indexer: v}
case MultiIndexer:
multiIndexer = v
default:
panic("The Indexer must also implement one of the SingleIndexer or MultiIndexer interfaces")
}
idx := &Index{
name: name,
indexer: multiIndexer,
}
for _, opt := range opts {
opt(idx)
}
return idx
}
func (i *Index) Name() string {
return i.name
}
View on GitHub (pinned to 2397ff0d76)
Solutions
- Implement the full SingleIndexer interface: FromArgs(...) ([]string, error) and FromObject(obj) ([]string, error)
- Pass a pointer if your indexer methods use pointer receivers: index.New("name", &myIndexer{})
- Add a compile-time assertion next to the type: var _ index.SingleIndexer = (*myIndexer)(nil)
Example fix
// before: only FromArgs implemented -> panic in type switch
type byKind struct{}
func (byKind) FromArgs(args ...any) ([]string, error) { ... }
idx := index.New("kind", byKind{})
// after: full SingleIndexer interface satisfied
type byKind struct{}
func (byKind) FromArgs(args ...any) ([]string, error) { ... }
func (byKind) FromObject(r *pbresource.Resource) ([]string, error) { ... }
var _ index.SingleIndexer = byKind{}
idx := index.New("kind", byKind{}) Defensive patterns
Strategy: type-guard
Validate before calling
// compile-time guarantee the indexer satisfies the framework interface var _ index.SingleIndexer = (*MyIndexer)(nil) // fails to build if methods are missing
Type guard
func implementsIndexer(i any) bool {
switch i.(type) {
case index.SingleIndexer, index.MultiIndexer:
return true
}
return false
} Prevention
- Copy the exact method signatures (including error returns) from the interface definition
- Pass pointers for pointer-receiver indexers: &myIndexer{}
- Keep a compile-time var _ assertion beside every custom indexer type
When it happens
Trigger: Passing a type that implements only part of the required method set (e.g. FromArgs but not FromObject), or a value type whose indexer methods have pointer receivers so the method set does not satisfy the interface, or a typed-nil pointer that matches no case.
Common situations: Writing a custom indexer and missing one method; passing a value instead of a pointer for pointer-receiver indexers; refactoring the index interfaces while custom indexers lag behind.
Related errors
- all indexers must have a non-empty name
- no indexer was supplied when creating a new cache Index
- a predefined cache query with name %q already exists
- reconciler must not be nil
- resource type %q already has a configured watch
AI-assisted analysis of hashicorp/consul@2397ff0d76 (2026-08-15).
Data as JSON: /api/errors/e21c6143a6a57283.
Report an issue: GitHub.