OpenNHP/opennhp · error

config load error

Error message

config load error

What it means

errLoadConfig is a package-level sentinel error in endpoints/db/config.go (mirrored by endpoints/ac/config.go) returned whenever the daemon's base/server/tees/resource config load or watch-update fails. It is also used as the panic-recovery value in updateBaseConfig, so any panic during a config reload is reported as this generic error. Because it is a plain sentinel, the underlying cause must be found in logs.

Solutions

  1. Validate each TOML file in etc/ (config.toml, server.toml, tees.toml, resource.toml) parses correctly.
  2. Check daemon logs immediately before the error for the real parse/watch failure.
  3. Restore file permissions and ensure the daemon user can read all config files.
  4. Compare configs against the shipped templates in endpoints/*/etc/ for field names and types.
  5. If triggered by a watch update, fix the last written change or redeploy the previous known-good config.

Example fix

// before: panic swallowed into generic sentinel
utils.CatchPanicThenRun(func() {
    err = errLoadConfig
})

// after: record the concrete cause too
utils.CatchPanicThenRun(func() {
    log.Error("panic during config update: %v", recover())
    err = fmt.Errorf("config load error: %w", errLoadConfig)
})
Defensive patterns

Strategy: validation

Validate before calling

for _, f := range []string{"config.toml", "server.toml", "tees.toml", "resource.toml"} {
    if _, err := toml.ParseFile(filepath.Join(etcDir, f)); err != nil {
        log.Fatalf("config %s invalid: %v", f, err)
    }
}

Type guard

func configReadable(dir string) bool {
    for _, f := range requiredConfigFiles {
        if fi, err := os.Stat(filepath.Join(dir, f)); err != nil || fi.IsDir() { return false }
    }
    return true
}

Try / catch

if err := ac.LoadConfig(); err != nil {
    if errors.Is(err, errLoadConfig) {
        log.Fatalf("config load failed — inspect logs and etc/*.toml: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: LoadConfig or updateBaseConfig fails: malformed/unreadable config.toml/server.toml/tees.toml/resource.toml, watch callback panics (recovered and converted to errLoadConfig), or type-conversion failures while parsing fields like LogLevel.

Common situations: TOML file edited by hand with syntax errors; missing config file at startup; wrong field types (string where int expected); etcd/file watcher delivering a partially written file that panics the parser; permissions changed on etc/ directory.

Understand the failure class

Background: "Config file not found": what it means and how to fix it in docker-sync, Maven, Vagrant, Turborepo and other tools — this error's family across 60 libraries.

Related errors


AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07). Data as JSON: /api/errors/bc20b7d8e7fc66c4. Report an issue: GitHub.

Appendix: source

Thrown at endpoints/db/config.go:23

	"io"
	"os"
	"path/filepath"

	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/log"
	"github.com/OpenNHP/opennhp/nhp/utils"
)

var (
	baseConfigWatch     io.Closer
	serverConfigWatch   io.Closer
	teesConfigWatch     io.Closer
	resourceConfigWatch io.Closer

	errLoadConfig = fmt.Errorf("config load error")
)

type Config struct {
	LogLevel            int
	PrivateKeyBase64    string
	DefaultCipherScheme int    `json:"defaultCipherScheme"`
	SymmetricCipherMode string `json:"symmetricCipherMode"`
	DbId                string `json:"dbId"`
}

// Peers is the top-level shape of server.toml. Each entry is one
// logical nhp-server identity (one pubkey) reachable at 1..N instances
// — same schema as nhp-agent's and nhp-ac's server.toml (see
// nhp/common/clusterconfig). nhp-db only ever talks to a single
// instance per cluster today, so LoadBalance / StickyInstance are
// loaded but ignored; the schema is shared so operators don't need a
// per-daemon dialect.
type Peers struct {

View on GitHub (pinned to 6e04ca5ff0)