{"record":{"id":"43a9641b8d9100f1","repo":"AdguardTeam/AdGuardHome","slug":"shutting-down-watcher-w","errorCode":null,"errorMessage":"shutting down watcher: %w","messagePattern":"shutting down watcher: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/aghtls/defaultmanager.go","lineNumber":272,"sourceCode":"func (mgr *DefaultManager) Start(ctx context.Context) (err error) {\n\terr = mgr.watcher.Start(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"starting watcher: %w\", err)\n\t}\n\n\tgo mgr.handleEvents(ctx)\n\tgo mgr.handleCertFileChange(ctx)\n\n\treturn nil\n}\n\n// Shutdown implements the [service.Interface] interface for *DefaultManager.\nfunc (mgr *DefaultManager) Shutdown(ctx context.Context) (err error) {\n\tdefer close(mgr.updates)\n\n\terr = mgr.watcher.Shutdown(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"shutting down watcher: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// Updates implements the [Manager] interface for *DefaultManager.\nfunc (mgr *DefaultManager) Updates(ctx context.Context) (updates <-chan UpdateSignal) {\n\treturn mgr.updates\n}\n\n// handleEvents handles changes of the tracked files.  It is intended to be run\n// in a separate goroutine.\nfunc (mgr *DefaultManager) handleEvents(ctx context.Context) {\n\tdefer slogutil.RecoverAndLog(ctx, mgr.logger)\n\n\teventsCh := mgr.watcher.Events()\n\tif eventsCh == nil {\n\t\tmgr.logger.DebugContext(ctx, \"watcher does not emit events\")","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/aghtls/defaultmanager.go#L254-L290","documentation":"Failed to stop the fsnotify watcher during TLS manager shutdown. Returned by DefaultManager.Shutdown when watcher.Shutdown returns an error; the updates channel is still closed via defer regardless.","triggerScenarios":"Calling Shutdown on a watcher that already failed or was never started, or when closing the inotify fd fails (rare; typically fd already closed elsewhere).","commonSituations":"Double-shutdown; shutting down a manager whose Start failed earlier; racing a Shutdown with a concurrently failing watcher goroutine.","solutions":["Treat as best-effort: log the error but continue process teardown if the process is exiting anyway","Ensure Shutdown is called exactly once and only after a successful Start","Check the wrapped error to confirm it is not masking a real resource leak"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := mgr.Shutdown(ctx); err != nil {\n    log.Warn(\"watcher shutdown issue (continuing)\", \"err\", err)\n}","preventionTips":["Only Shutdown managers that started successfully","Shutdown once, from a single teardown path"],"tags":["tls","fsnotify","shutdown","lifecycle"],"backgroundTag":"shutdown-cleanup-failed","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}