{"record":{"id":"22b64baa9b517f13","repo":"OpenNHP/opennhp","slug":"private-key-parse-error-v","errorCode":null,"errorMessage":"private key parse error %v","messagePattern":"private key parse error (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"endpoints/ac/udpac.go","lineNumber":136,"sourceCode":"\t\ta.ipset, err = utils.NewIPSet(false)\n\t\tif err != nil {\n\t\t\tlog.Error(\"ipset command not found\")\n\t\t\treturn\n\t\t}\n\tcase FilterMode_EBPFXDP:\n\t\terr = ebpflocal.EbpfEngineLoad(dirPath, logLevel, a.config.ACId)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\tdefault:\n\t\tlog.Error(\"[HandleAccessControl] unsupported FilterMode: %d (expected 0=IPTABLES or 1=EBPFXDP)\", a.config.FilterMode)\n\t\treturn\n\t}\n\n\tprk, err := base64.StdEncoding.DecodeString(a.config.PrivateKeyBase64)\n\tif err != nil {\n\t\tlog.Error(\"private key parse error %v\\n\", err)\n\t\treturn fmt.Errorf(\"private key parse error %v\", err)\n\t}\n\n\ta.device = core.NewDevice(core.NHP_AC, prk, nil)\n\tif a.device == nil {\n\t\tlog.Critical(\"failed to create device %v\\n\", err)\n\t\treturn fmt.Errorf(\"failed to create device %v\", err)\n\t}\n\n\ta.remoteConnectionMap = make(map[string]*UdpConn)\n\ta.serverPeerMap = make(map[string]*core.UdpPeer)\n\ta.tokenStore = common.NewTokenStore[*AccessEntry]()\n\n\tif a.etcdConn != nil {\n\t\t_ = a.loadRemoteConfig()\n\t} else {\n\t\t// load http config and turn on http server if needed\n\t\t_ = a.loadHttpConfig()\n","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/endpoints/ac/udpac.go#L118-L154","documentation":"UdpAC.Start fails with \"private key parse error %v\" when the AC's config.PrivateKeyBase64 cannot be decoded with base64.StdEncoding. The decoded bytes must be a valid Curve25519/SM2 private key for core.NewDevice; a decode failure aborts startup before any device is created.","triggerScenarios":"PrivateKeyBase64 in config.toml contains whitespace/newlines, uses URL-safe base64 or raw hex, includes the '-----BEGIN...' PEM wrapper, or is empty/placeholder text generated outside `keygen --curve/--sm2 --json`.","commonSituations":"Hand-editing config.toml and pasting a key with quotes/line breaks; copying an ed25519 or hex key from another tool; mixing curve and SM2 key formats; shell truncating the key during provisioning.","solutions":["Regenerate the key with `./nhp-acd keygen --curve --json` and paste only the base64 body (no quotes, no whitespace)","Strip whitespace/newlines before decoding: base64.StdEncoding.DecodeString(strings.TrimSpace(...)) or wrap in strings.Join(strings.Fields(k), \"\")","Confirm the key matches the configured cipher scheme (curve vs SM2)","Validate the config at load time with a base64 decode check so the failure surfaces with a clear field name"],"exampleFix":"// before\nprk, err := base64.StdEncoding.DecodeString(a.config.PrivateKeyBase64)\nif err != nil {\n\treturn fmt.Errorf(\"private key parse error %v\", err)\n}\n// after\ncleaned := strings.Join(strings.Fields(a.config.PrivateKeyBase64), \"\")\nprk, err := base64.StdEncoding.DecodeString(cleaned)\nif err != nil {\n\treturn fmt.Errorf(\"private key parse error (invalid base64 in config.toml PrivateKeyBase64): %w\", err)\n}","handlingStrategy":"validation","validationCode":"k := strings.TrimSpace(conf.PrivateKeyBase64)\nif k == \"\" { return fmt.Errorf(\"privateKeyBase64 is empty\") }\nif _, err := base64.StdEncoding.DecodeString(k); err != nil {\n\treturn fmt.Errorf(\"privateKeyBase64 is not valid std base64: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"prk, err := base64.StdEncoding.DecodeString(a.config.PrivateKeyBase64)\nif err != nil {\n\treturn fmt.Errorf(\"invalid privateKeyBase64 in config.toml: %w\", err)\n}","preventionTips":["Generate keys only via `nhp-acd keygen --json` and paste the raw base64 body","Strip whitespace/newlines from pasted keys","Validate base64 fields at config load time, before Start"],"tags":["config","base64","crypto","startup"],"backgroundTag":"invalid-argument-format","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"}