{"record":{"id":"0aab6d7764a49a38","repo":"XTLS/Xray-core","slug":"invalid-privatekey","errorCode":null,"errorMessage":"invalid \"privateKey\": ","messagePattern":"invalid \"privateKey\": ","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"infra/conf/transport_security.go","lineNumber":101,"sourceCode":"\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`)\n\t\t} else {\n\t\t\tconfig.MinClientVer = []byte{26, 3, 27} // change it at your own risk: https://github.com/XTLS/Xray-core/commit/af7eb68028732a8ee3c0e5d6ab2b8a657bb2e770\n\t\t\terrors.LogWarning(context.Background(), `REALITY: The default minimal client version is Xray-core v26.3.27, other clients may be refused to connect`)","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/infra/conf/transport_security.go#L83-L119","documentation":"Thrown by the REALITY builder when privateKey fails base64 RawURL decoding or decodes to a length != 32 bytes. REALITY private keys are 32-byte x25519 scalars encoded in unpadded base64url; anything else (standard base64 with padding, hex, a pasted public key, or trailing whitespace) is rejected, and the offending value is echoed in the message.","triggerScenarios":"Putting the PUBLIC key into privateKey, using base64 with '=' padding, including a newline/space, or hand-editing the key string.","commonSituations":"Swapping the two lines output by 'xray x25519'; copying keys through a terminal that wraps/truncates lines.","solutions":["Regenerate with 'xray x25519' and copy the Private key line verbatim (43 chars, no padding, no whitespace).","Ensure the server uses privateKey and clients use publicKey.","Paste with a terminal/editor that does not add line breaks."],"exampleFix":"// before\n\"privateKey\": \"MIIBvQIBADAN...==\"  // padded / wrong key\n// after\n\"privateKey\": \"Ux8Fq2m1nQ0jK3pR7sT9vW2xY4zA6bC8dE0fG1hI\"  // from `xray x25519`","handlingStrategy":"validation","validationCode":"func validX25519Key(s string) bool {\n    s = strings.TrimSpace(s)\n    raw, err := base64.RawURLEncoding.DecodeString(s)\n    return err == nil && len(raw) == 32\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always generate keys with 'xray x25519' and copy verbatim.","Strip whitespace on paste; reject keys containing '=' padding."],"tags":["config","reality","x25519","base64","keys","validation","go"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}