OpenNHP/opennhp · error

failed to open file

Error message

failed to open file: %w

What it means

Md5sum opens the (already stat-validated) file with os.Open; if the open syscall fails despite the successful Stat — typically due to a permission race, an unreadable symlink target, or too many open files — the underlying error is wrapped as "failed to open file: %w". This is distinct from the not-found and not-regular-file checks that run first.

Solutions

  1. Check file permissions (ls -l) and grant read access to the process user, e.g. chmod o+r or chown to the service user
  2. Re-check the fd limit (ulimit -n / systemd LimitNOFILE) and raise it if EMFILE appears in the wrapped error
  3. Confirm the file still exists at the exact moment of the call (race between Stat and Open implies concurrent deletion — stabilize the deployment)
  4. Inspect the wrapped inner error (%w) to distinguish EACCES from EMFILE or EIO

Example fix

// before (deployment)
-rw------- root root /opt/nhp/ta.so
// after
chown nhp:nhp /opt/nhp/ta.so && chmod 0400 /opt/nhp/ta.so
Defensive patterns

Strategy: validation

Validate before calling

f, err := os.Open(p); if err != nil { return err }; f.Close()

Prevention

When it happens

Trigger: os.Stat succeeds but os.Open fails: the file was removed between Stat and Open; the file's permission bits deny read access to the process user; the fd limit (ulimit -n) is exhausted; the file is on a failing mount.

Common situations: Running the daemon as a non-root user while the TA/plugin file is root-only (0600 root:root); NFS/FUSE mount dropped between checks; very high fd usage in a long-running process hitting EMFILE.

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


AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07). Data as JSON: /api/errors/a14b06553c62d61f. Report an issue: GitHub.

Appendix: source

Thrown at nhp/utils/crypto.go:136

	return base64.StdEncoding.EncodeToString(pivKey), base64.StdEncoding.EncodeToString(pubKey)
}

// Md5sum computes MD5 checksum for file integrity verification (not cryptographic security)
//
//nolint:gosec // G401: MD5 used for file integrity checksums, not for cryptographic security
func Md5sum(fullFilePath string) (string, error) {
	fileInfo, err := os.Stat(fullFilePath)
	if err != nil {
		return "", fmt.Errorf("file not found: %w", err)
	}

	if !fileInfo.Mode().IsRegular() {
		return "", fmt.Errorf("path is not a regular file")
	}

	file, err := os.Open(fullFilePath) //nolint:gosec // G304: Path validated by os.Stat above
	if err != nil {
		return "", fmt.Errorf("failed to open file: %w", err)
	}
	defer file.Close()

	hasher := md5.New()

	if _, err := io.Copy(hasher, file); err != nil {
		return "", fmt.Errorf("failed to read file content: %w", err)
	}

	// Convert hash to hex string
	return hex.EncodeToString(hasher.Sum(nil)), nil
}

View on GitHub (pinned to 6e04ca5ff0)