OpenNHP/opennhp · error
relay: failed to read config
Error message
relay: failed to read config %s: %w
What it means
Raised by relay LoadConfig when os.ReadFile on the config path (the given path, or etc/config.toml under the executable directory) fails with an error other than not-exist — typically a permission problem, an unreadable directory, or an I/O error. A missing file is handled separately with a warning and defaults; this error means the file exists but cannot be read.
Solutions
- Check file permissions on the config path (chmod/chown so the relay process can read it)
- Confirm the path points to a regular file, not a directory or broken symlink
- If SELinux/AppArmor is enforced, allow the service to read its etc directory
- Fix the underlying I/O issue (disk, mount) if that is the cause
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at endpoints/relay/config.go:157 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/1b501f010240ca2f.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/relay/config.go:157
}
}
// LoadConfig reads a TOML config file. If path is empty it defaults to
// etc/config.toml relative to ExeDirPath.
func LoadConfig(path string) (*Config, error) {
cfg := DefaultConfig()
if path == "" {
path = filepath.Join(ExeDirPath, "etc", "config.toml")
}
data, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
log.Warning("[Relay] config file %s not found, using defaults", path)
return cfg, nil
}
return nil, fmt.Errorf("relay: failed to read config %s: %w", path, err)
}
if err := toml.Unmarshal(data, cfg); err != nil {
return nil, fmt.Errorf("relay: failed to parse config %s: %w", path, err)
}
if err := cfg.normalize(); err != nil {
return nil, err
}
log.Info("[Relay] loaded config from %s with %d server(s)", path, len(cfg.Servers))
return cfg, nil
}
// normalize validates the configuration and applies legacy-field migration so
// that the rest of the relay only has to look at Config.Servers. It is
// exported as a method (not a function) to make it directly testable on a
// hand-built Config in unit tests without round-tripping through TOML.View on GitHub (pinned to 6e04ca5ff0)