OpenNHP/opennhp · error
config load error
Error message
config load error
What it means
errLoadConfig is a sentinel error returned by UdpAC.updateBaseConfig and UdpAC.updateHttpConfig when a config reload callback panics; utils.CatchPanicThenRun recovers the panic and the named return err is set to errLoadConfig so callers see a config load failure instead of a crash. It signals that a config file (base, http, or server peer) could not be applied.
Solutions
- Inspect ac logs immediately preceding the panic to find the actual panic value and stack from utils.CatchPanicThenRun
- Validate the TOML files (config.toml, http.toml) types and required fields before saving; restart nhp-ac with known-good config
- Fix the reload code to validate Config fields before mutating live state, so bad files return a normal error instead of panicking
- Check for a race between the file watcher and readers sharing the config struct; add locking or snapshot swap
Example fix
// before
func (a *UdpAC) updateBaseConfig(conf Config) (err error) {
utils.CatchPanicThenRun(func() { err = errLoadConfig })
...
}
// after
func (a *UdpAC) updateBaseConfig(conf Config) (err error) {
if conf.ListenAddress == "" || conf.PrivateKeyBase64 == "" {
return fmt.Errorf("invalid base config: missing required fields")
}
utils.CatchPanicThenRun(func() { err = errLoadConfig })
...
} Defensive patterns
Strategy: try-catch
Validate before calling
// validate TOML before save
var c ac.Config
if _, err := toml.DecodeFile("config.toml", &c); err != nil { return err }
if c.ListenAddress == "" || c.PrivateKeyBase64 == "" { return fmt.Errorf("config.toml incomplete") } Try / catch
if err := a.UpdateBaseConfig(conf); err != nil {
if errors.Is(err, ac.ErrLoadConfig) {
log.Error("config reload panicked; keeping previous config")
}
} Prevention
- Validate TOML files with a dry-run decode before saving
- Write config atomically (temp file + rename) so watchers never see partial files
- Add unit tests for the reload path with malformed configs
When it happens
Trigger: A panic occurs inside the config-watch/reload code path of updateBaseConfig (endpoints/ac/config.go:242) or updateHttpConfig (endpoints/ac/config.go:278), e.g. nil dereference or type assertion failure while applying a freshly loaded Config/HttpConfig from the TOML watcher.
Common situations: Editing config.toml or http.toml while nhp-ac is running with a value that makes the reload code panic (wrong type in TOML that slips past unmarshal, missing map entries); hot-reload race where the watcher fires with a partially written file.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- unknown remote provider
- unknown remote provider
- key not found
- value not set
- cluster instance # : must set either Host or Ip
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/7133f8654bbc57a1.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/ac/config.go:26
"path/filepath"
"strconv"
"strings"
toml "github.com/pelletier/go-toml/v2"
"github.com/OpenNHP/opennhp/nhp/common/clusterconfig"
"github.com/OpenNHP/opennhp/nhp/core"
"github.com/OpenNHP/opennhp/nhp/etcd"
"github.com/OpenNHP/opennhp/nhp/log"
"github.com/OpenNHP/opennhp/nhp/utils"
)
var (
baseConfigWatch io.Closer
httpConfigWatch io.Closer
serverPeerWatch io.Closer
errLoadConfig = fmt.Errorf("config load error")
)
const (
FilterMode_IPTABLES = iota // 0
FilterMode_EBPFXDP // 1
)
// ACEtcdConfig is the remote-config (etcd) shape. Servers carries the
// shared cluster schema so the etcd value is identical to the on-disk
// server.toml. The previous Endpoints-string form lived only on this
// branch and is removed in the AC → ClusterConfig migration; redeploy
// any etcd values written under that schema.
type ACEtcdConfig struct {
BaseConfig Config
HttpConfig HttpConfig
Servers []*clusterconfig.ClusterConfig
}
View on GitHub (pinned to 6e04ca5ff0)