{"record":{"id":"436118cdeb782028","repo":"OpenNHP/opennhp","slug":"relay-failed-to-parse-config-s-w","errorCode":null,"errorMessage":"relay: failed to parse config %s: %w","messagePattern":"relay: failed to parse config (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"endpoints/relay/config.go","lineNumber":161,"sourceCode":"// etc/config.toml relative to ExeDirPath.\nfunc LoadConfig(path string) (*Config, error) {\n\tcfg := DefaultConfig()\n\n\tif path == \"\" {\n\t\tpath = filepath.Join(ExeDirPath, \"etc\", \"config.toml\")\n\t}\n\n\tdata, err := os.ReadFile(path)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\tlog.Warning(\"[Relay] config file %s not found, using defaults\", path)\n\t\t\treturn cfg, nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"relay: failed to read config %s: %w\", path, err)\n\t}\n\n\tif err := toml.Unmarshal(data, cfg); err != nil {\n\t\treturn nil, fmt.Errorf(\"relay: failed to parse config %s: %w\", path, err)\n\t}\n\n\tif err := cfg.normalize(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tlog.Info(\"[Relay] loaded config from %s with %d server(s)\", path, len(cfg.Servers))\n\treturn cfg, nil\n}\n\n// normalize validates the configuration and applies legacy-field migration so\n// that the rest of the relay only has to look at Config.Servers. It is\n// exported as a method (not a function) to make it directly testable on a\n// hand-built Config in unit tests without round-tripping through TOML.\nfunc (cfg *Config) normalize() error {\n\tif cfg.PrivateKeyBase64 == \"\" {\n\t\treturn fmt.Errorf(\"relay: privateKeyBase64 must be set in config\")\n\t}","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/endpoints/relay/config.go#L143-L179","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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)"],"exampleFix":"// before (invalid TOML)\nprivateKeyBase64 = abc123\n[Servers]\npubKeyBase64 = \"...\"\n// after\nprivateKeyBase64 = \"abc123\"\n[[Servers]]\npubKeyBase64 = \"...\"","handlingStrategy":"validation","validationCode":"// Go: validate config TOML before startup\ndata, err := os.ReadFile(path)\nif err != nil { return err }\nvar probe map[string]any\nif _, err := toml.Unmarshal(data, &probe); err != nil {\n\treturn fmt.Errorf(\"config %s is not valid TOML: %w\", path, err)\n}\ncfg, err := relay.LoadConfig(path)\nif err != nil { log.Fatalf(\"relay config error: %v\", err) }","typeGuard":null,"tryCatchPattern":"cfg, err := relay.LoadConfig(path)\nif err != nil {\n\treturn fmt.Errorf(\"startup aborted, fix relay config: %w\", err)\n}","preventionTips":["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"],"tags":["relay","config","toml","startup"],"backgroundTag":"schema-validation-failed","analyzedSha":"6e04ca5ff03222a699c24205cd4bf8fee9af7ffe","analyzedAt":"2026-09-07T15:44:59.941Z","contentChangedAt":"2026-09-07T15:44:59.941Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}