hashicorp/nomad · error
failed to read hash file %s
Error message
failed to read hash file %s
What it means
This error is returned by ResolvConf.UserModified when reading the sidecar hash file (rcHashPath) that stores the digest of the resolv.conf contents fails with an error other than fs.ErrNotExist. The library hashes /etc/resolv.conf and persists the digest so it can later tell whether the file was modified outside the process. If the hash file cannot be read (permissions, I/O error), the modification state is unknowable, so the error is wrapped and returned instead of guessed.
Source
Thrown at lib/resolvconf/lib.go:416
}
}
return nil
}
// UserModified can be used to determine whether the resolv.conf file has been
// modified since it was generated. It returns false with no error if the file
// matches the hash, true with no error if the file no longer matches the hash,
// 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) {View on GitHub (pinned to 482b49bf1a)
Solutions
- Check and fix permissions/ownership of the hash file (rcHashPath) so the process user can read it: ls -l <rcHashPath>, then chmod/chown accordingly.
- Verify the hash file path points to a regular readable file, not a directory or broken symlink; recreate it if corrupted.
- Re-run the component as the same user that originally wrote the hash file, or delete the stale hash file so UserModified treats the file as unmodified.
- Check filesystem health / disk errors (dmesg) if reads fail on otherwise valid files.
- Regenerate the hash file via the library's Set path so the next UserModified call succeeds.
Example fix
// before (hash file unreadable, running as non-root) // -rw------- root root /var/run/resolvconf.hash // UserModified() -> failed to read hash file ... // after // sudo chown appuser:appuser /var/run/resolvconf.hash // sudo chmod 600 /var/run/resolvconf.hash // UserModified() -> (false, nil)
Defensive patterns
Strategy: fallback
Validate before calling
if h, err := os.Stat(rcHashPath); err != nil || h.IsDir() {
// hash file unreadable: treat as unmodified or re-initialize state
} Type guard
func hashFileReadable(path string) bool {
f, err := os.Open(path)
if err != nil { return false }
f.Close()
return true
} Try / catch
modified, err := rc.UserModified()
if err != nil {
if strings.Contains(err.Error(), "failed to read hash file") {
log.Warnf("hash file unreadable, assuming unmodified: %v", err)
modified = false
} else {
return err
}
} Prevention
- Keep the process user consistent with whoever created the hash file (avoid mixing root/non-root runs).
- Ensure the state directory has correct ownership and is writable before startup.
- Recreate a stale or suspicious hash file instead of forcing reads of it.
- Monitor filesystem health to catch read errors early.
When it happens
Trigger: Calling ResolvConf.UserModified when the hash file exists but cannot be read: permission denied on the hash file path, an I/O error reading it, or the path being a directory/unreadable special file. A missing hash file returns (false, nil), not this error.
Common situations: Running in a container where the hash file was created by a different user (running the agent as non-root after an earlier run as root); read-only or full filesystem; state directory mounted with wrong ownership; security software blocking access to the file.
Related errors
- failed to open %s to check for modifications
- 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/644d48e24bfb8731.
Report an issue: GitHub.