OpenNHP/opennhp · error
relay: failed to parse config
Error message
relay: failed to parse config %s: %w
What it means
LoadConfig reads the relay TOML file and hands it to toml.Unmarshal; this error wraps any parse failure with the file path. It means the config file exists but is not valid TOML or does not match the Config struct (e.g. wrong types), so the relay cannot build its runtime configuration. It is thrown by endpoints/relay/config.go's LoadConfig, which the app calls during startup.
Solutions
- Run the file through a TOML linter/parser (e.g. tomlq or an online validator) to find the syntax error on the reported line
- Compare field names/types in config.toml against the Config struct in endpoints/relay/config.go
- Restore the file from the repo's example/template config and re-apply changes incrementally
- Check that the file was not corrupted or truncated in transfer (diff against a known-good copy)
Example fix
// before (invalid TOML) privateKeyBase64 = abc123 [Servers] pubKeyBase64 = "..." // after privateKeyBase64 = "abc123" [[Servers]] pubKeyBase64 = "..."
Defensive patterns
Strategy: validation
Validate before calling
// Go: validate config TOML before startup
data, err := os.ReadFile(path)
if err != nil { return err }
var probe map[string]any
if _, err := toml.Unmarshal(data, &probe); err != nil {
return fmt.Errorf("config %s is not valid TOML: %w", path, err)
}
cfg, err := relay.LoadConfig(path)
if err != nil { log.Fatalf("relay config error: %v", err) } Try / catch
cfg, err := relay.LoadConfig(path)
if err != nil {
return fmt.Errorf("startup aborted, fix relay config: %w", err)
} Prevention
- Run the config through a TOML linter in CI before deploying
- Keep a known-good template config in the repo and diff changes against it
- Add a startup smoke test that loads the shipped example config
When it happens
Trigger: LoadConfig is called by runApp at startup with a path to a config.toml whose contents fail toml.Unmarshal — malformed TOML syntax (missing quotes, bad indentation, duplicate keys) or a type mismatch with the Config struct (e.g. string where an integer port is expected).
Common situations: Hand-editing config.toml and introducing a TOML syntax error; copying a Linux config to another environment with a mangled encoding; renaming a table key like [Servers] incorrectly; using TOML 1.0 features unsupported by the pinned toml library version.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- server peer config invalid on initial load
- config load error
- load db peer config err (optional)
- load relay peer config err (optional)
- private key parse error
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/436118cdeb782028.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/relay/config.go:161
// 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.
func (cfg *Config) normalize() error {
if cfg.PrivateKeyBase64 == "" {
return fmt.Errorf("relay: privateKeyBase64 must be set in config")
}View on GitHub (pinned to 6e04ca5ff0)