OpenNHP/opennhp · error
error reading file
Error message
error reading file: %v
What it means
ReadZdtoConfig opened `etc/ztdo/data-<doId>.json` but io.ReadAll failed while reading its contents. The wrapped OS error (commonly EIO from failing disk or I/O on a network volume) prevents loading the DRGMsg.
Solutions
- Check the wrapped OS error (dmesg / storage health) and repair the underlying disk or remount the volume.
- Verify data-<doId>.json is a regular file, not a device/FIFO, and replace it if corrupted.
- Re-publish the ZTDO via the DRG flow to rewrite the config from source.
- If on network storage, ensure the mount is healthy before retrying.
Example fix
// before: no file-type check
file, _ := os.Open(configFilePath)
// after: ensure a regular file before reading
fi, _ := file.Stat()
if !fi.Mode().IsRegular() {
return common.DRGMsg{}, fmt.Errorf("%s is not a regular file", configFilePath)
} Defensive patterns
Strategy: fallback
Validate before calling
p := filepath.Join(exeDir, "etc", "ztdo", "data-"+doId+".json")
fi, err := os.Stat(p)
if err == nil && !fi.Mode().IsRegular() {
return fmt.Errorf("%s is not a regular file", p)
} Type guard
func isReadableRegularFile(p string) bool {
fi, err := os.Stat(p)
return err == nil && fi.Mode().IsRegular()
} Try / catch
msg, err := ReadZdtoConfig(doId)
if err != nil && strings.Contains(err.Error(), "error reading file") {
log.Error("ztdo IO failure: %v", err) // fallback to cache/re-publish
return loadFromBackupOrRepublish(doId)
} Prevention
- Monitor storage health (SMART, dmesg) on the server volume.
- Keep configs on local reliable disk rather than flaky network mounts.
- Back up etc/ztdo so damaged configs can be restored.
When it happens
Trigger: HandleDHPDARMessage/HandleDHPDAVMessage or SaveZdtoConfig trigger ReadZdtoConfig on a config file whose read fails — rare, typically hardware/IO errors, detached network storage, or file changed to a special file (device/FIFO).
Common situations: etc/ztdo lives on an NFS/EBS volume that dropped; underlying disk errors; someone replaced the JSON file with a named pipe or device node.
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
- error reading file
- could not open file
- fail to read resource
- already exists, please delete it first
- failed to create config.json
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/0ac4059e980b164b.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/server/msghandler.go:761
encoder := json.NewEncoder(file)
encoder.SetIndent("", " ")
return encoder.Encode(drgMsg)
}
// read data-<doId>.json to DRGMsg Object
func ReadZdtoConfig(doId string) (common.DRGMsg, error) {
etcDir := filepath.Join(ExeDirPath, "etc", "ztdo")
configFilePath := filepath.Join(etcDir, "data-"+doId+".json")
file, err := os.Open(configFilePath)
if err != nil {
return common.DRGMsg{}, fmt.Errorf("could not open file: %v", err)
}
defer file.Close()
fileContentByte, err := io.ReadAll(file)
if err != nil {
return common.DRGMsg{}, fmt.Errorf("error reading file: %v", err)
}
var config common.DRGMsg
err = json.Unmarshal(fileContentByte, &config)
if err != nil {
return common.DRGMsg{}, fmt.Errorf("json parsing error: %s", err)
}
return config, nil
}
// HandleRelayForward processes a decrypted NHP_RLY message from the standard
// Noise pipeline. The relay's identity has already been validated by
// validatePeer as part of the standard decryption flow.
//
// The message body is a JSON-encoded RelayForwardMsg containing:
// - SourceAddr: the real client's IP/port
// - InnerPacket: base64-encoded inner NHP packet (encrypted by agent)View on GitHub (pinned to 6e04ca5ff0)