XTLS/Xray-core · error
invalid "privateKey":
Error message
invalid "privateKey":
What it means
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.
Source
Thrown at infra/conf/transport_security.go:101
if _, _, err = net.SplitHostPort(s); err == nil {
c.Type = "tcp"
}
}
}
if c.Type == "" {
return nil, errors.New(`please fill in a valid value for "target"`)
}
if c.Xver > 2 {
return nil, errors.New(`invalid PROXY protocol version, "xver" only accepts 0, 1, 2`)
}
if len(c.ServerNames) == 0 {
return nil, errors.New(`empty "serverNames"`)
}
if c.PrivateKey == "" {
return nil, errors.New(`empty "privateKey"`)
}
if config.PrivateKey, err = base64.RawURLEncoding.DecodeString(c.PrivateKey); err != nil || len(config.PrivateKey) != 32 {
return nil, errors.New(`invalid "privateKey": `, c.PrivateKey)
}
if c.MinClientVer != "" {
config.MinClientVer = make([]byte, 3)
var u uint64
for i, s := range strings.Split(c.MinClientVer, ".") {
if i == 3 {
return nil, errors.New(`invalid "minClientVer": `, c.MinClientVer)
}
if u, err = strconv.ParseUint(s, 10, 8); err != nil {
return nil, errors.New(`"minClientVer[`, i, `]" should be less than 256`)
} else {
config.MinClientVer[i] = byte(u)
}
}
errors.LogWarning(context.Background(), `REALITY: Changing "minClientVer" will increase the likelihood of your server's IP being blocked by the GFW`)
} else {
config.MinClientVer = []byte{26, 3, 27} // change it at your own risk: https://github.com/XTLS/Xray-core/commit/af7eb68028732a8ee3c0e5d6ab2b8a657bb2e770
errors.LogWarning(context.Background(), `REALITY: The default minimal client version is Xray-core v26.3.27, other clients may be refused to connect`)View on GitHub (pinned to 7d214f8b09)
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.
Example fix
// before "privateKey": "MIIBvQIBADAN...==" // padded / wrong key // after "privateKey": "Ux8Fq2m1nQ0jK3pR7sT9vW2xY4zA6bC8dE0fG1hI" // from `xray x25519`
Defensive patterns
Strategy: validation
Validate before calling
func validX25519Key(s string) bool {
s = strings.TrimSpace(s)
raw, err := base64.RawURLEncoding.DecodeString(s)
return err == nil && len(raw) == 32
} Prevention
- Always generate keys with 'xray x25519' and copy verbatim.
- Strip whitespace on paste; reject keys containing '=' padding.
When it happens
Trigger: Putting the PUBLIC key into privateKey, using base64 with '=' padding, including a newline/space, or hand-editing the key string.
Common situations: Swapping the two lines output by 'xray x25519'; copying keys through a terminal that wraps/truncates lines.
Related errors
- empty "privateKey"
- Invalid base64 string
- REALITY: Empty "realitySettings".
- please fill in a valid value for "target"
- invalid PROXY protocol version, "xver" only accepts 0, 1, 2
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/0aab6d7764a49a38.
Report an issue: GitHub.