OpenNHP/opennhp · critical

invalid CookieSigningKeyBase64

Error message

invalid CookieSigningKeyBase64: %w

What it means

UdpServer.Start refuses to boot when CookieSigningKeyBase64 is present in the config but not valid base64 (or decodes to an unusable key). The server deliberately fails fast instead of silently falling back to a per-process random key, because in a cluster each replica minting cookies a sibling cannot verify would break stateless cookie auth while looking healthy.

Solutions

  1. Re-run the base64 encoder over the raw key and paste only the exact single-line base64 output into CookieSigningKeyBase64
  2. Verify the value decodes: `echo '<value>' | base64 -d | wc -c` and confirm it yields a 32-byte key
  3. Regenerate a fresh key with the daemon's keygen command and use its base64 output
  4. If no shared key is intended, remove the field entirely so Start generates a random per-process key (single-instance only)

Example fix

// before (config.toml)
CookieSigningKeyBase64 = "aGVsbG8gd29ybGQ=  "  # trailing space/newline breaks decode
// after
CookieSigningKeyBase64 = "<openssl rand -base64 32 output, trimmed>"
Defensive patterns

Strategy: validation

Validate before calling

key := cfg.CookieSigningKeyBase64
if key != "" {
    if _, err := base64.StdEncoding.DecodeString(strings.TrimSpace(key)); err != nil {
        return fmt.Errorf("config: CookieSigningKeyBase64 is not valid base64: %w", err)
    }
}

Prevention

When it happens

Trigger: Calling Start (via runApp) with a config.toml whose CookieSigningKeyBase64 is set to a non-empty string that fails base64 decoding or key validation in the cookie-key parsing step.

Common situations: Operators hand-editing config.toml and pasting a key with whitespace/quotes/truncation; secret managers returning the base64 of a base64; copying a key from docs with placeholder characters; CI templating leaving stray characters in the field.

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


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

Appendix: source

Thrown at endpoints/server/udpserver.go:292

		log.Critical("failed to create device: %v", err)
		return fmt.Errorf("failed to create device %v", err)
	}

	// Stateless cookie signing key. In a multi-instance cluster all
	// nhp-server replicas must share the same value so any of them can
	// verify a cookie that a sibling minted. When the operator hasn't
	// configured one we mint a random per-process key — fine for a single
	// instance, broken for a cluster (the failure is silent: cookies
	// minted by replica A don't verify on replica B and the agent's RKN
	// stalls until timeout). Always log which mode we're in.
	cookieKey, cookieKeyErr := decodeCookieSigningKey(s.config.CookieSigningKeyBase64)
	if cookieKeyErr != nil {
		// Malformed (not empty) is an ops mistake — fail fast rather
		// than silently degrading to a per-process random key. Silent
		// fallback would let a cluster look healthy while its replicas
		// each mint cookies a sibling can't verify.
		log.Critical("invalid CookieSigningKeyBase64 in config: %v", cookieKeyErr)
		return fmt.Errorf("invalid CookieSigningKeyBase64: %w", cookieKeyErr)
	}
	if len(cookieKey) == 0 {
		cookieKey = make([]byte, 32)
		if _, readErr := rand.Read(cookieKey); readErr != nil {
			log.Critical("failed to generate random cookie signing key: %v", readErr)
			return fmt.Errorf("failed to generate random cookie signing key: %v", readErr)
		}
		log.Info("CookieSigningKeyBase64 not set; using a random per-process key (single-instance only — clusters must share an operator-supplied key)")
	} else {
		log.Info("CookieSigningKeyBase64 configured; cookies are stateless and shared across the cluster")
		// Catch operators who copy the docker-compose demo config and
		// forget to regenerate the shared key. The shipped value is
		// public (committed to docker/nhp-server/etc/config.toml so
		// `docker-compose up` works out of the box) — running it in
		// any environment a real client can reach lets anyone who has
		// browsed the repo mint cookies the server will accept.
		// Critical (not Warning) so it surfaces in default journalctl
		// filters and any oncall log-volume alarms.

View on GitHub (pinned to 6e04ca5ff0)