hashicorp/consul · error
a predefined cache query with name %q already exists
Error message
a predefined cache query with name %q already exists
What it means
Controller.WithQuery registers a named cache query that reconcilers and dependency mappers can look up by string during execution. Query names form the lookup namespace; registering the same name twice panics because the second registration would silently shadow the first and change behavior depending on registration order.
Source
Thrown at internal/controller/controller.go:133
panic(fmt.Sprintf("resource type %q already has a configured watch", key))
}
w := newWatch(watchedType, mapper)
for _, idx := range indexes {
w.addIndex(idx)
}
ctl.watches[key] = w
return ctl
}
// WithQuery will add a named query to the controllers cache for usage during reconcile or in dependency mappers
func (ctl *Controller) WithQuery(queryName string, fn cache.Query) *Controller {
_, duplicate := ctl.queries[queryName]
if duplicate {
panic(fmt.Sprintf("a predefined cache query with name %q already exists", queryName))
}
ctl.queries[queryName] = fn
return ctl
}
// WithCustomWatch adds a new custom watch. Custom watches do not affect the controller cache.
func (ctl *Controller) WithCustomWatch(source *Source, mapper CustomDependencyMapper) *Controller {
if source == nil {
panic("source must not be nil")
}
if mapper == nil {
panic("mapper must not be nil")
}
ctl.customWatches = append(ctl.customWatches, customWatch{source, mapper})
return ctlView on GitHub (pinned to 2397ff0d76)
Solutions
- Give each query a unique name (constants help: const QueryByKind = "by-kind")
- Consolidate registration of shared queries into a single helper called once
- When registering from multiple modules, keep a set of used names and skip or error on duplicates before calling WithQuery
Example fix
// before
ctl.WithQuery("by-name", byName)
ctl.WithQuery("by-name", byNameV2) // panic: already exists
// after
ctl.WithQuery("by-name", byName)
ctl.WithQuery("by-name-v2", byNameV2) Defensive patterns
Strategy: validation
Validate before calling
// deduplicate query names before registering
names := map[string]bool{}
for name, fn := range queries {
if names[name] {
return fmt.Errorf("duplicate cache query name %q", name)
}
names[name] = true
ctl.WithQuery(name, fn)
} Prevention
- Define query names as exported constants shared by registration and lookup sites
- Register shared queries in one helper invoked once per controller
- Smoke-test full controller construction in CI so duplicates fail early
When it happens
Trigger: Calling WithQuery("name", fn) twice with the same name on one Controller — typically copy-pasted registration blocks, two modules independently registering a common helper query, or refactored setup code that double-registers.
Common situations: Splitting controller wiring across files that both register a shared query; merging controller setups; renaming a query to a name already in use.
Related errors
- all indexers must have a non-empty name
- no indexer was supplied when creating a new cache Index
- The Indexer must also implement one of the SingleIndexer or
- resource type %q already has a configured watch
- reconciler must not be nil
AI-assisted analysis of hashicorp/consul@2397ff0d76 (2026-08-15).
Data as JSON: /api/errors/bf4bf50aba989ed8.
Report an issue: GitHub.