OpenNHP/opennhp · error

failed to read file

Error message

failed to read file: %w

What it means

LoadJsonFileAsStruct reads the file with os.ReadFile and wraps any read failure. This means the path was non-empty but the OS could not open/read it - typically the file does not exist, or permission prevents reading, or the path is a directory. The OS error is wrapped with %w.

Solutions

  1. Check the file exists at the exact path (ls -l / os.Stat) before loading; create it via SaveStructAsJsonFile if absent.
  2. Match errors with errors.Is(err, fs.ErrNotExist) vs fs.ErrPermission to decide between 'generate it' and 'fix permissions'.
  3. Use absolute paths built from a known base directory instead of relative paths that depend on the daemon's CWD.
  4. Fix ownership/permissions (chown/chmod) so the daemon's user can read the file.

Example fix

// before
raw, err := utils.LoadJsonFileAsStruct("etc/ta.json")
// after
if _, statErr := os.Stat("etc/ta.json"); errors.Is(statErr, fs.ErrNotExist) {
    if mkErr := utils.SaveStructAsJsonFile("etc/ta.json", defaultTA); mkErr != nil { return mkErr }
}
raw, err := utils.LoadJsonFileAsStruct("etc/ta.json")
Defensive patterns

Strategy: validation

Validate before calling

if info, err := os.Stat(path); err != nil {
    return fmt.Errorf("TA file missing: %w", err)
} else if info.IsDir() {
    return fmt.Errorf("%s is a directory", path)
}

Try / catch

data, err := utils.LoadJsonFileAsStruct(path)
if err != nil {
    if errors.Is(err, fs.ErrNotExist) { /* generate default file, retry once */ }
    else if errors.Is(err, fs.ErrPermission) { /* report permission problem */ }
}

Prevention

When it happens

Trigger: Calling LoadJsonFileAsStruct with a path whose file was never created (e.g. SaveStructAsJsonFile was never run or failed), a typo'd path, or a file readable only by root while the daemon runs as a lower-privileged user.

Common situations: registerTAService runs on first boot before the trust-anchor file is generated; key/TA file rotated or deleted externally; working-directory difference makes relative paths resolve elsewhere; NFS/permission issues in container deployments.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: source

Thrown at nhp/utils/utils.go:140

		return fmt.Errorf("failed to marshal data to JSON: %w", err)
	}

	err = os.WriteFile(filePath, jsonData, 0644) //nolint:gosec // G306: Generic utility - callers determine sensitivity
	if err != nil {
		return fmt.Errorf("failed to write JSON to file: %w", err)
	}

	return nil
}

func LoadJsonFileAsStruct(filePath string) (any, error) {
	if filePath == "" {
		return nil, fmt.Errorf("file path cannot be empty")
	}

	jsonData, err := os.ReadFile(filePath)
	if err != nil {
		return nil, fmt.Errorf("failed to read file: %w", err)
	}

	var data map[string]any

	if err := json.Unmarshal(jsonData, &data); err != nil {
		return nil, fmt.Errorf("failed to unmarshal JSON %s to struct: %w", string(jsonData), err)
	}

	return data, nil
}

func UpdateTomlConfig(filePath string, key string, value any) error {
	content, err := os.ReadFile(filePath)
	if err != nil {
		return err
	}

	var newContent string

View on GitHub (pinned to 6e04ca5ff0)