micro/go-micro · error
watcher is disabled
Error message
watcher is disabled
What it means
The memory loader supports disabling watchers via the WithWatcherDisabled loader option. When that option is set, Watch returns "watcher is disabled" immediately without creating a watcher. This is an intentional configuration guard, not a runtime failure — the application was explicitly configured not to support config watching.
Source
Thrown at config/loader/memory/memory.go:361
if !m.opts.WithWatcherDisabled {
go m.watch(idx, source)
}
}
if err := m.reload(); err != nil {
gerrors = append(gerrors, err.Error())
}
// Return errors
if len(gerrors) != 0 {
return errors.New(strings.Join(gerrors, "\n"))
}
return nil
}
func (m *memory) Watch(path ...string) (loader.Watcher, error) {
if m.opts.WithWatcherDisabled {
return nil, errors.New("watcher is disabled")
}
value, err := m.Get(path...)
if err != nil {
return nil, err
}
m.Lock()
w := &watcher{
exit: make(chan bool),
path: path,
value: value,
reader: m.opts.Reader,
updates: make(chan updateValue, 1),
}
w.version.Store(m.snap.Version)
View on GitHub (pinned to 24529f1404)
Solutions
- Remove the WithWatcherDisable option when constructing the loader if watching is desired.
- If disabling is intentional, guard the Watch call with a feature flag/config check and skip watching instead of erroring.
- Poll Get on an interval as a fallback where watchers are disabled.
- Check loader.Options() (or your wiring) to confirm whether watcher support is off before attempting Watch.
Example fix
// before
loader := memory.NewLoader(memory.WithWatcherDisable())
w, _ := loader.Watch()
// after
loader := memory.NewLoader() // watchable
w, err := loader.Watch()
if err != nil {
log.Fatal(err)
} Defensive patterns
Strategy: fallback
Validate before calling
if watcherDisabled {
log.Println("config watching disabled; using polling")
return nil
}
w, err := loader.Watch()
if err != nil {
return err
} Try / catch
w, err := loader.Watch()
if err != nil {
if err.Error() == "watcher is disabled" {
return startPoller(loader, interval)
}
return err
} Prevention
- Keep a single place that decides whether watching is enabled.
- Only pass WithWatcherDisable when the app explicitly opts out of dynamic config.
- Gate Watch calls on the same flag used to construct the loader.
- Document the disabled-watcher behavior in team config conventions.
When it happens
Trigger: Calling loader.Watch(path...) — or config.Watch which delegates to it — on a memory loader constructed with memory.WithWatcherDisable(), or with a config that passes that option through.
Common situations: Environments (serverless, batch jobs, tests) where dynamic config reload is intentionally disabled for performance, but shared library code unconditionally sets up a watcher; copying setup code that includes the disable option without realizing it blocks Watch.
Related errors
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/6d094bee3ed03bab.
Report an issue: GitHub.