{"record":{"id":"6d094bee3ed03bab","repo":"micro/go-micro","slug":"watcher-is-disabled","errorCode":null,"errorMessage":"watcher is disabled","messagePattern":"watcher is disabled","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/loader/memory/memory.go","lineNumber":361,"sourceCode":"\t\tif !m.opts.WithWatcherDisabled {\n\t\t\tgo m.watch(idx, source)\n\t\t}\n\t}\n\n\tif err := m.reload(); err != nil {\n\t\tgerrors = append(gerrors, err.Error())\n\t}\n\n\t// Return errors\n\tif len(gerrors) != 0 {\n\t\treturn errors.New(strings.Join(gerrors, \"\\n\"))\n\t}\n\treturn nil\n}\n\nfunc (m *memory) Watch(path ...string) (loader.Watcher, error) {\n\tif m.opts.WithWatcherDisabled {\n\t\treturn nil, errors.New(\"watcher is disabled\")\n\t}\n\n\tvalue, err := m.Get(path...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tm.Lock()\n\n\tw := &watcher{\n\t\texit:    make(chan bool),\n\t\tpath:    path,\n\t\tvalue:   value,\n\t\treader:  m.opts.Reader,\n\t\tupdates: make(chan updateValue, 1),\n\t}\n\tw.version.Store(m.snap.Version)\n","sourceCodeStart":343,"sourceCodeEnd":379,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/config/loader/memory/memory.go#L343-L379","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nloader := memory.NewLoader(memory.WithWatcherDisable())\nw, _ := loader.Watch()\n// after\nloader := memory.NewLoader() // watchable\nw, err := loader.Watch()\nif err != nil {\n    log.Fatal(err)\n}","handlingStrategy":"fallback","validationCode":"if watcherDisabled {\n    log.Println(\"config watching disabled; using polling\")\n    return nil\n}\nw, err := loader.Watch()\nif err != nil {\n    return err\n}","typeGuard":null,"tryCatchPattern":"w, err := loader.Watch()\nif err != nil {\n    if err.Error() == \"watcher is disabled\" {\n        return startPoller(loader, interval)\n    }\n    return err\n}","preventionTips":["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."],"tags":["config","loader","watcher","go","configuration-guard"],"backgroundTag":"watcher-disabled","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}