{"record":{"id":"dc5cc9b3db5c3284","repo":"hashicorp/nomad","slug":"failed-to-open-s-to-check-for-modifications","errorCode":null,"errorMessage":"failed to open %s to check for modifications","messagePattern":"failed to open (.+?) to check for modifications","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/resolvconf/lib.go","lineNumber":425,"sourceCode":"// and false with an error if the result cannot be determined.\nfunc UserModified(rcPath, rcHashPath string) (bool, error) {\n\tcurrRCHash, err := os.ReadFile(rcHashPath)\n\tif err != nil {\n\t\t// If the hash file doesn't exist, can only assume it hasn't been written\n\t\t// yet (so, the user hasn't modified the file it hashes).\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn false, nil\n\t\t}\n\t\treturn false, errors.Wrapf(err, \"failed to read hash file %s\", rcHashPath)\n\t}\n\texpected, err := digest.Parse(string(currRCHash))\n\tif err != nil {\n\t\treturn false, errors.Wrapf(err, \"failed to parse hash file %s\", rcHashPath)\n\t}\n\tv := expected.Verifier()\n\tcurrRC, err := os.Open(rcPath)\n\tif err != nil {\n\t\treturn false, errors.Wrapf(err, \"failed to open %s to check for modifications\", rcPath)\n\t}\n\tdefer currRC.Close()\n\tif _, err := io.Copy(v, currRC); err != nil {\n\t\treturn false, errors.Wrapf(err, \"failed to hash %s to check for modifications\", rcPath)\n\t}\n\treturn !v.Verified(), nil\n}\n\nfunc (rc *ResolvConf) processLine(line string) {\n\tfields := strings.Fields(line)\n\n\t// Strip blank lines and comments.\n\tif len(fields) == 0 || fields[0][0] == '#' || fields[0][0] == ';' {\n\t\treturn\n\t}\n\n\tswitch fields[0] {\n\tcase \"nameserver\":","sourceCodeStart":407,"sourceCodeEnd":443,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/lib/resolvconf/lib.go#L407-L443","documentation":"This error is returned by ResolvConf.UserModified when it successfully parsed the stored digest and built a verifier, but os.Open on the actual resolv.conf (rcPath) fails. To compare the stored hash against the live file the library must open it; a failure to open means the modification check cannot be performed, so the underlying error is wrapped and returned.","triggerScenarios":"Calling ResolvConf.UserModified when rcPath does not exist, the process lacks read permission on it, rcPath is a dangling symlink, or opening the path fails due to file-descriptor exhaustion or filesystem errors.","commonSituations":"resolv.conf deleted or replaced by a dangling symlink in containers where it is bind-mounted; running as non-root while resolv.conf is root-only; EMFILE in long-running daemons; missing mount of /etc/resolv.conf in minimal containers/chroots.","solutions":["Verify rcPath exists and is a readable regular file: ls -l <rcPath>; recreate resolv.conf or fix the dangling symlink.","Fix permissions so the process user can read rcPath (it is normally world-readable 0644).","Check for file-descriptor leaks if the error is 'too many open files' and raise ulimit -n if legitimately needed.","In containers, ensure /etc/resolv.conf is mounted/managed as expected (not a dangling symlink into an unmounted volume)."],"exampleFix":"// before: dangling symlink\n// ls -l /etc/resolv.conf -> broken symlink to /run/systemd/resolve/stub-resolv.conf\n// UserModified() -> failed to open ... to check for modifications\n\n// after\n// sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf\n// UserModified() -> (true/false, nil)","handlingStrategy":"validation","validationCode":"if fi, err := os.Stat(rcPath); err != nil {\n\t// rcPath missing or inaccessible before calling UserModified\n} else if !fi.Mode().IsRegular() {\n\t// not a regular file (symlink/directory)\n}","typeGuard":"func resolvConfReadable(path string) bool {\n\tfi, err := os.Stat(path)\n\treturn err == nil && fi.Mode().IsRegular()\n}","tryCatchPattern":"modified, err := rc.UserModified()\nif err != nil && strings.Contains(err.Error(), \"failed to open\") {\n\tif errors.Is(err, fs.ErrNotExist) {\n\t\t// resolv.conf missing: recreate default or skip check\n\t}\n\treturn err\n}","preventionTips":["Verify /etc/resolv.conf exists and is a valid symlink/regular file in containers.","Ensure the process user has read access (resolv.conf is normally 0644).","Watch fd usage in long-running daemons to avoid EMFILE.","Ensure resolv.conf is properly mounted, not a dangling symlink."],"tags":["resolvconf","filesystem","dns","permissions"],"backgroundTag":"file-open-failed","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}