MHSanaei/3x-ui · error

wireguard preSharedKey: %w

Error message

wireguard preSharedKey: %w

What it means

Same KeyToHex validation applied to the optional 'preSharedKey'. Because the field is optional, an absent key yields "" from getOptionalUserString — so reaching this error means a value WAS provided and it is malformed (bad base64 or not 32 bytes). An empty/absent PSK does not error; only a present-but-invalid one does.

Source

Thrown at internal/xray/api.go:639

			Auth: auth,
		}), nil
	case "wireguard":
		pubB64, err := getRequiredUserString(user, "publicKey")
		if err != nil {
			return nil, err
		}
		pubHex, err := wgutil.KeyToHex(pubB64)
		if err != nil {
			return nil, fmt.Errorf("wireguard publicKey: %w", err)
		}

		pskB64, err := getOptionalUserString(user, "preSharedKey")
		if err != nil {
			return nil, err
		}
		pskHex, err := wgutil.KeyToHex(pskB64)
		if err != nil {
			return nil, fmt.Errorf("wireguard preSharedKey: %w", err)
		}

		allowed := collectStringSlice(user["allowedIPs"])
		if len(allowed) == 0 {
			return nil, common.NewError("wireguard: allowedIPs required")
		}

		keepAlive, err := getOptionalUserString(user, "keepAlive")
		if err != nil {
			return nil, err
		}

		return serial.ToTypedMessage(&wireguard.PeerConfig{
			PublicKey:    pubHex,
			PreSharedKey: pskHex,
			AllowedIps:   allowed,
			KeepAlive:    keepAlive,
		}), nil

View on GitHub (pinned to ad32144c42)

Solutions

  1. Either remove the preSharedKey field entirely (optional, valid), or supply a proper 32-byte base64 key generated by 'wg genpsk'.
  2. Same length check as publicKey: 43 unpadded base64 chars; convert hex if that's what you have.
  3. Trim whitespace/newlines when copying PSKs out of files or chat messages.

Example fix

// before
user["preSharedKey"] = "none"

// after
// option A: no PSK — omit the key entirely
// option B: real PSK from `wg genpsk`
user["preSharedKey"] = base64FromWgGenpsk
Defensive patterns

Strategy: validation

Validate before calling

// PSK: either omit or validate like any 32-byte base64 key
if psk, present := user["preSharedKey"]; present {
    s, _ := psk.(string)
    if !isValidWGKeyB64(s) {
        delete(user, "preSharedKey") // optional field: removal is safe
    }
}

Type guard

null

Try / catch

if strings.Contains(err.Error(), "wireguard preSharedKey") {
    // remove the field or supply a `wg genpsk` value; no retry
}

Prevention

When it happens

Trigger: Setting preSharedKey to a hex string, a PSK of the wrong length, or a value with stray characters/whitespace; also pasting the string 'none' or 'false' as a placeholder instead of removing the field.

Common situations: Config migrations carrying hex-form PSKs; users entering placeholder text in an optional field; PSK copied with a trailing newline from a file.

Related errors


AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15). Data as JSON: /api/errors/da39b2ce9f4904a1. Report an issue: GitHub.