AlexxIT/go2rtc · error

hap: VerifyServerAuthenticator

Error message

hap: VerifyServerAuthenticator

What it means

In Pair's STEP M4, the client verifies the server's SRP proof (M4) with session.VerifyServerAuthenticator. Failure means the accessory did not prove it knows the same SRP secret derived from the setup PIN — i.e. the PIN is wrong, the device is not in pairing mode, or the pairing handshake desynchronized.

Solutions

  1. Re-enter the setup PIN carefully (8 digits, from the device label/HomeKit setup card) and retry Pair.
  2. Confirm the accessory accepts new pairings: remove the device from any other HomeKit controller first.
  3. Power-cycle the accessory and start a fresh Pair session (new SRP session) — never reuse a half-finished session.
  4. If the device consistently fails M4 with the correct PIN, factory-reset it and pair again.

Example fix

// before: single Pair attempt with a possibly mistyped PIN
err := client.Pair("0314520")
// after: normalize the PIN (digits only) and surface a clear message on failure
pin := strings.ReplaceAll(cfg.PIN, "-", "")
if len(pin) != 8 { return errors.New("setup PIN must be 8 digits") }
if err := client.Pair(pin); err != nil {
    if strings.Contains(err.Error(), "VerifyServerAuthenticator") {
        return errors.New("pairing rejected: wrong setup PIN or device already paired")
    }
    return err
}
Defensive patterns

Strategy: try-catch

Validate before calling

pin := strings.ReplaceAll(setupCode, "-", "")
if len(pin) != 8 {
    return errors.New("setup PIN must be exactly 8 digits")
}

Try / catch

if err := client.Pair(pin); err != nil {
    if strings.Contains(err.Error(), "VerifyServerAuthenticator") {
        // wrong PIN, device already paired, or not in pairing mode:
        // re-prompt the user and start a fresh Pair session
        return errors.New("pairing rejected: check the setup PIN and that the device accepts pairings")
    }
    return err
}

Prevention

When it happens

Trigger: Typing an incorrect setup code (the 8-digit PIN on the device label); the accessory is already paired to another controller and rejects a new pairing; M1-M3 exchange corrupted by a flaky connection; device firmware rejecting pairing while not in allow-pairing state.

Common situations: User misreading the PIN (ambiguous characters, confusing 0/O or 1/I); attempting to pair a camera that was already paired from a phone; pairing immediately after power-on before the HAP server accepts pairings.

Understand the failure class

Related errors


AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07). Data as JSON: /api/errors/0aa140dc7b2d4219. Report an issue: GitHub.

Appendix: source

Thrown at pkg/hap/client_pairing.go:173

		Proof string `tlv8:"4"` // server proof
		State byte   `tlv8:"6"`
		Error byte   `tlv8:"7"`

		EncryptedData string `tlv8:"5"` // skip EncryptedData validation (for MFi devices)
	}
	if err = tlv8.UnmarshalReader(res.Body, res.ContentLength, &plainM4); err != nil {
		return
	}
	if plainM4.State != StateM4 {
		return newResponseError(plainM3, plainM4)
	}
	if plainM4.Error != 0 {
		return newPairingError(plainM4.Error)
	}

	// STEP M4. Verify response
	if !session.VerifyServerAuthenticator([]byte(plainM4.Proof)) {
		return errors.New("hap: VerifyServerAuthenticator")
	}

	// STEP M5. Generate signature
	localSign, err := hkdf.Sha512(
		sessionShared, "Pair-Setup-Controller-Sign-Salt", "Pair-Setup-Controller-Sign-Info",
	)
	if err != nil {
		return
	}

	b := Append(localSign, c.ClientID, c.ClientPublic())
	signature, err := ed25519.Signature(c.ClientPrivate, b)
	if err != nil {
		return
	}

	// STEP M5. Generate payload
	plainM5 := struct {

View on GitHub (pinned to c245815e75)