{"record":{"id":"76cc05720034fa3d","repo":"containerd/containerd","slug":"cni-network-conf-monitor-error-w","errorCode":null,"errorMessage":"cni network conf monitor error: %w","messagePattern":"cni network conf monitor error: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/cri/server/service.go","lineNumber":396,"sourceCode":"\t}\n\t// If the error is set above, err from channel must be nil here, because\n\t// the channel is supposed to be closed. Or else, we wait and set it.\n\tif err := <-eventMonitorErrCh; err != nil {\n\t\teventMonitorErr = err\n\t}\n\tlog.L.Info(\"Event monitor stopped\")\n\tif err := <-streamServerErrCh; err != nil {\n\t\tstreamServerErr = err\n\t}\n\tlog.L.Info(\"Stream server stopped\")\n\tif eventMonitorErr != nil {\n\t\treturn fmt.Errorf(\"event monitor error: %w\", eventMonitorErr)\n\t}\n\tif streamServerErr != nil {\n\t\treturn fmt.Errorf(\"stream server error: %w\", streamServerErr)\n\t}\n\tif cniNetConfMonitorErr != nil {\n\t\treturn fmt.Errorf(\"cni network conf monitor error: %w\", cniNetConfMonitorErr)\n\t}\n\treturn nil\n}\n\n// Close stops the CRI service.\n// TODO(random-liu): Make close synchronous.\nfunc (c *criService) Close() error {\n\tlog.L.Info(\"Stop CRI service\")\n\tfor name, h := range c.cniNetConfMonitor {\n\t\tif err := h.stop(); err != nil {\n\t\t\tlog.L.WithError(err).Errorf(\"failed to stop cni network conf monitor for %s\", name)\n\t\t}\n\t}\n\tc.eventMonitor.Stop()\n\tif c.statsCollector != nil {\n\t\tc.statsCollector.Stop()\n\t}\n\tif err := c.streamServer.Stop(); err != nil {","sourceCodeStart":378,"sourceCodeEnd":414,"githubUrl":"https://github.com/containerd/containerd/blob/4246446a2bf7d03837b0244118d858799393bd80/internal/cri/server/service.go#L378-L414","documentation":"criService.Run starts a cniNetConfSyncer loop per CNI network config monitor (flannel and default networks); if any syncLoop exits with an error, Run tears down the entire CRI service and returns this wrapped error, last in priority after event monitor and stream server errors. It means the CNI network configuration watching/synchronization loop failed, so pod networking config can no longer be kept in sync.","triggerScenarios":"h.syncLoop() in the cniNetConfSyncer returns non-nil: watching the CNI conf directory (e.g. /etc/cni/net.d) fails (inotify errors, directory missing), reading/parsing a CNI network config file fails, or the syncer's context is cancelled with an error.","commonSituations":"/etc/cni/net.d removed or unreadable on the node (CNI plugin files deleted by a broken uninstall); malformed CNI .conflist written by a network plugin installer; permission problems after host hardening; flannel syncer failing on nodes where the flannel subnet env file is missing.","solutions":["Check the wrapped inner error and which syncer name was logged at startup ('Start cni network conf syncer for %s') to identify the failing network.","Verify the CNI config directory (/etc/cni/net.d) exists, is readable by containerd, and contains valid .conflist/.conf JSON (run jq against each file).","Reinstall or repair the CNI network plugin (e.g. flannel/calico manifests) so its config files and subnet env are regenerated.","Check inotify limits (fs.inotify.max_user_watches) if the inner error indicates watch creation failure.","Restart containerd after fixing the CNI config so the syncers restart cleanly."],"exampleFix":"// before: malformed CNI config\n/etc/cni/net.d/10-flannel.conflist  (truncated JSON)\n\n// after: restore a valid conflist or remove the broken file, then\nsudo systemctl restart containerd","handlingStrategy":"validation","validationCode":"// before starting containerd, sanity-check CNI config dir\nimport (\n    \"encoding/json\"\n    \"os\"\n    \"path/filepath\"\n)\n\nfunc validateCNIConfDir(dir string) error {\n    if _, err := os.Stat(dir); err != nil {\n        return fmt.Errorf(\"CNI conf dir %s missing/unreadable: %w\", dir, err)\n    }\n    files, _ := filepath.Glob(filepath.Join(dir, \"*.conf*\"))\n    for _, f := range files {\n        b, err := os.ReadFile(f)\n        if err != nil {\n            return err\n        }\n        if !json.Valid(b) {\n            return fmt.Errorf(\"malformed CNI config: %s\", f)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate every file in /etc/cni/net.d parses as JSON before deploying node changes.","Ensure CNI plugin uninstallers don't delete the conf directory out from under containerd.","Keep directory permissions readable by the containerd user (root:root 0644/0755).","Raise fs.inotify.max_user_watches on nodes with many watched config dirs.","After any CNI plugin install/upgrade, restart containerd and confirm syncer startup logs appear."],"tags":["cri","containerd","cni","networking","config-monitor"],"backgroundTag":"cni-config-sync-failed","analyzedSha":"4246446a2bf7d03837b0244118d858799393bd80","analyzedAt":"2026-09-02T00:14:43.053Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}