{"record":{"id":"dbef158b093f5537","repo":"ory/hydra","slug":"file-watch-v","errorCode":null,"errorMessage":"file watch: %v","messagePattern":"file watch: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"oryx/tlsx/cert.go","lineNumber":185,"sourceCode":"\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\n\t\t\tcase event := <-events:\n\t\t\t\tvar err error\n\t\t\t\tswitch event := event.(type) {\n\t\t\t\tcase *watcherx.ChangeEvent:\n\t\t\t\t\tvar cert tls.Certificate\n\t\t\t\t\tcert, err = tls.LoadX509KeyPair(certPath, keyPath)\n\t\t\t\t\tif err == nil {\n\t\t\t\t\t\tstore.Store(&cert)\n\t\t\t\t\t\tlastReportedError = \"\"\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\terr = fmt.Errorf(\"unable to load X509 key pair from files: %v\", err)\n\n\t\t\t\tcase *watcherx.ErrorEvent:\n\t\t\t\t\terr = fmt.Errorf(\"file watch: %v\", event)\n\t\t\t\tdefault:\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif err.Error() == lastReportedError { // same message as before: don't spam the error channel\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\t// fresh error\n\t\t\t\tselect {\n\t\t\t\tcase errs <- errors.WithStack(err):\n\t\t\t\t\tlastReportedError = err.Error()\n\t\t\t\tcase <-time.After(500 * time.Millisecond):\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn func(*tls.ClientHelloInfo) (*tls.Certificate, error) {","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/ory/hydra/blob/4174065ffb052799890f7480f5360a877a67ffc1/oryx/tlsx/cert.go#L167-L203","documentation":"In the same watcher loop, when a watcherx.ErrorEvent arrives (the file watcher itself failed — e.g. permission error, vanished directory, filesystem error), the event is wrapped as \"file watch: %v\" and forwarded to the error channel. It signals a problem watching the certificate files, not necessarily bad certificate content.","triggerScenarios":"A *watcherx.ErrorEvent is received while watching certPath/keyPath: watched file deleted, directory removed, permission revoked, or the underlying fsnotify backend errored.","commonSituations":"Kubernetes secret volume being swapped/recreated, tmpfs cleanup removing the watched path, container filesystem restrictions, or inotify limits exhausted on the host.","solutions":["Check that the watched cert/key paths still exist and remain accessible to the process","Inspect the underlying watcher error in the message and fix the filesystem cause (permissions, mounts, inotify limits: fs.inotify.max_user_watches)","Ensure secret volumes are not being unmounted/recreated in a way that removes the watched files","Restart the service after the filesystem issue is resolved; the error channel consumer should log and keep the last good cert"],"exampleFix":"// before: consumer ignores error channel\n// after\ngo func() {\n    for err := range errCh {\n        log.WithError(err).Warn(\"tls cert watcher problem\") // e.g. \"file watch: ...\"\n        // alert / check mounts\n    }\n}()","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"for err := range errCh {\n    if strings.HasPrefix(err.Error(), \"file watch:\") {\n        log.WithError(err).Warn(\"certificate file watcher error; check mounts/permissions/inotify limits\")\n    }\n}","preventionTips":["Ensure watched paths persist for the process lifetime (no unmount/removal)","Raise fs.inotify.max_user_watches if watchers are exhausted","Monitor the error channel and alert on repeated watch errors"],"tags":["tls","file-watcher","filesystem","inotify"],"backgroundTag":"file-watch-error","analyzedSha":"4174065ffb052799890f7480f5360a877a67ffc1","analyzedAt":"2026-09-03T14:52:41.581Z","contentChangedAt":"2026-09-03T14:52:41.581Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}