hashicorp/nomad · error
failed to open %s to check for modifications
Error message
failed to open %s to check for modifications
What it means
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.
Source
Thrown at lib/resolvconf/lib.go:425
// and false with an error if the result cannot be determined.
func UserModified(rcPath, rcHashPath string) (bool, error) {
currRCHash, err := os.ReadFile(rcHashPath)
if err != nil {
// If the hash file doesn't exist, can only assume it hasn't been written
// yet (so, the user hasn't modified the file it hashes).
if errors.Is(err, fs.ErrNotExist) {
return false, nil
}
return false, errors.Wrapf(err, "failed to read hash file %s", rcHashPath)
}
expected, err := digest.Parse(string(currRCHash))
if err != nil {
return false, errors.Wrapf(err, "failed to parse hash file %s", rcHashPath)
}
v := expected.Verifier()
currRC, err := os.Open(rcPath)
if err != nil {
return false, errors.Wrapf(err, "failed to open %s to check for modifications", rcPath)
}
defer currRC.Close()
if _, err := io.Copy(v, currRC); err != nil {
return false, errors.Wrapf(err, "failed to hash %s to check for modifications", rcPath)
}
return !v.Verified(), nil
}
func (rc *ResolvConf) processLine(line string) {
fields := strings.Fields(line)
// Strip blank lines and comments.
if len(fields) == 0 || fields[0][0] == '#' || fields[0][0] == ';' {
return
}
switch fields[0] {
case "nameserver":View on GitHub (pinned to 482b49bf1a)
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).
Example fix
// before: dangling symlink // ls -l /etc/resolv.conf -> broken symlink to /run/systemd/resolve/stub-resolv.conf // UserModified() -> failed to open ... to check for modifications // after // sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf // UserModified() -> (true/false, nil)
Defensive patterns
Strategy: validation
Validate before calling
if fi, err := os.Stat(rcPath); err != nil {
// rcPath missing or inaccessible before calling UserModified
} else if !fi.Mode().IsRegular() {
// not a regular file (symlink/directory)
} Type guard
func resolvConfReadable(path string) bool {
fi, err := os.Stat(path)
return err == nil && fi.Mode().IsRegular()
} Try / catch
modified, err := rc.UserModified()
if err != nil && strings.Contains(err.Error(), "failed to open") {
if errors.Is(err, fs.ErrNotExist) {
// resolv.conf missing: recreate default or skip check
}
return err
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
- failed to read hash file %s
- failed to hash %s to check for modifications
- plugin not executable
- failed to snapshot %s: %w
- error creating task %q dir: %w
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/dc5cc9b3db5c3284.
Report an issue: GitHub.