{"record":{"id":"cdcc9637a00fad02","repo":"XTLS/Xray-core","slug":"empty-privatekey","errorCode":null,"errorMessage":"empty \"privateKey\"","messagePattern":"empty \"privateKey\"","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"infra/conf/transport_security.go","lineNumber":98,"sourceCode":"\t\t\t\tif _, err = strconv.Atoi(s); err == nil {\n\t\t\t\t\ts = \"localhost:\" + s\n\t\t\t\t}\n\t\t\t\tif _, _, err = net.SplitHostPort(s); err == nil {\n\t\t\t\t\tc.Type = \"tcp\"\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif c.Type == \"\" {\n\t\t\treturn nil, errors.New(`please fill in a valid value for \"target\"`)\n\t\t}\n\t\tif c.Xver > 2 {\n\t\t\treturn nil, errors.New(`invalid PROXY protocol version, \"xver\" only accepts 0, 1, 2`)\n\t\t}\n\t\tif len(c.ServerNames) == 0 {\n\t\t\treturn nil, errors.New(`empty \"serverNames\"`)\n\t\t}\n\t\tif c.PrivateKey == \"\" {\n\t\t\treturn nil, errors.New(`empty \"privateKey\"`)\n\t\t}\n\t\tif config.PrivateKey, err = base64.RawURLEncoding.DecodeString(c.PrivateKey); err != nil || len(config.PrivateKey) != 32 {\n\t\t\treturn nil, errors.New(`invalid \"privateKey\": `, c.PrivateKey)\n\t\t}\n\t\tif c.MinClientVer != \"\" {\n\t\t\tconfig.MinClientVer = make([]byte, 3)\n\t\t\tvar u uint64\n\t\t\tfor i, s := range strings.Split(c.MinClientVer, \".\") {\n\t\t\t\tif i == 3 {\n\t\t\t\t\treturn nil, errors.New(`invalid \"minClientVer\": `, c.MinClientVer)\n\t\t\t\t}\n\t\t\t\tif u, err = strconv.ParseUint(s, 10, 8); err != nil {\n\t\t\t\t\treturn nil, errors.New(`\"minClientVer[`, i, `]\" should be less than 256`)\n\t\t\t\t} else {\n\t\t\t\t\tconfig.MinClientVer[i] = byte(u)\n\t\t\t\t}\n\t\t\t}\n\t\t\terrors.LogWarning(context.Background(), `REALITY: Changing \"minClientVer\" will increase the likelihood of your server's IP being blocked by the GFW`)","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/infra/conf/transport_security.go#L80-L116","documentation":"Thrown by the REALITY builder when the privateKey field is an empty string. The private key is the server's long-term REALITY identity (x25519); without it no handshakes can be authenticated, so the builder refuses.","triggerScenarios":"Omitting privateKey in realitySettings or setting it to \"\".","commonSituations":"Client-side configs accidentally including a realitySettings block (privateKey is server-only; clients use publicKey/fingerprint), or the key never generated.","solutions":["Generate a key pair with 'xray x25519' and put the private key on the server.","If editing a client config, remove privateKey and use \"publicKey\" + \"fingerprint\" instead."],"exampleFix":"// before\n\"realitySettings\": { \"target\": \"www.microsoft.com:443\", \"serverNames\": [\"www.microsoft.com\"] }\n// after\n\"realitySettings\": { \"target\": \"www.microsoft.com:443\", \"serverNames\": [\"www.microsoft.com\"], \"privateKey\": \"Ux5Z...\" }","handlingStrategy":"validation","validationCode":"if reality.PrivateKey == \"\" {\n    return errors.New(\"server-side REALITY requires privateKey (generate with `xray x25519`)\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never deploy a REALITY server config without running x25519 key generation first.","Client configs use publicKey, not privateKey — catch this in review."],"tags":["config","reality","x25519","keys","validation","go"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}