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

  1. Check and fix permissions/ownership of the hash file (rcHashPath) so the process user can read it: ls -l <rcHashPath>, then chmod/chown accordingly.
  2. Verify the hash file path points to a regular readable file, not a directory or broken symlink; recreate it if corrupted.
  3. 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.
  4. Check filesystem health / disk errors (dmesg) if reads fail on otherwise valid files.
  5. 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

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


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/644d48e24bfb8731. Report an issue: GitHub.