{"record":{"id":"886a2e11800fb766","repo":"AdguardTeam/AdGuardHome","slug":"refreshing-w","errorCode":null,"errorMessage":"refreshing: %w","messagePattern":"refreshing: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"internal/aghtls/defaultmanager.go","lineNumber":247,"sourceCode":"\t}\n\n\terr := mgr.watcher.Add(p)\n\tif err != nil {\n\t\terrs = append(errs, fmt.Errorf(\"watching %s %s: %w\", what, p, err))\n\t}\n\n\treturn errs\n}\n\n// Refresh implements the [service.Refresher] interface for *DefaultManager.\nfunc (mgr *DefaultManager) Refresh(ctx context.Context) (err error) {\n\tmgr.logger.DebugContext(ctx, \"refreshing\")\n\n\tselect {\n\tcase mgr.updates <- UpdateSignal{}:\n\t\treturn nil\n\tcase <-ctx.Done():\n\t\treturn fmt.Errorf(\"refreshing: %w\", ctx.Err())\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// Start implements the [service.Interface] interface for *DefaultManager.\nfunc (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","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/aghtls/defaultmanager.go#L229-L265","documentation":"Refresh signals the TLS manager that configuration changed by pushing to its updates channel; this error occurs only when the passed context is cancelled before the non-blocking send succeeds (or immediately). It wraps context.Canceled or context.DeadlineExceeded.","triggerScenarios":"Calling mgr.Refresh(ctx) with an already-cancelled context or one whose deadline expires at the same moment the updates channel is full, so the ctx.Done() branch wins the select.","commonSituations":"Calling Refresh during shutdown when the root context is already cancelled; Refreshing from a request-scoped context that times out; concurrent Refresh calls racing with Shutdown closing the updates channel.","solutions":["Use a long-lived context (not request-scoped or already-cancelled) for Refresh","Check ctx.Err() before calling Refresh and skip if cancelled","Retry Refresh after shutdown completes on a fresh manager instance"],"exampleFix":"// before\nmgr.Refresh(reqCtx) // reqCtx may already be cancelled\n// after\nif err := mgr.Refresh(longLivedCtx); err != nil { /* log, non-fatal */ }","handlingStrategy":"try-catch","validationCode":"if ctx.Err() != nil {\n    return ctx.Err()\n}","typeGuard":null,"tryCatchPattern":"if err := mgr.Refresh(ctx); err != nil {\n    if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {\n        return // benign during shutdown\n    }\n    return err\n}","preventionTips":["Pass a process-lifetime context to Refresh, never a request context","Do not Refresh concurrently with Shutdown"],"tags":["tls","context","refresh","cancellation"],"backgroundTag":"context-canceled","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}