gravitational/teleport · info

device already holds a registered credential

Error message

device already holds a registered credential

What it means

errHasExcludedCredential is a user-friendly device filter error in the FIDO2 device filter. When during a registration the device already holds a credential listed in the excludeCredentials list (or libfido2 reports ErrUserPresenceRequired, which YubiKey4 uses to signal an existing credential), the device is filtered out with this error instead of attempting a duplicate registration.

Source

Thrown at lib/auth/webauthncli/fido2.go:66

	// goroutine.
	fido2DeviceMaxWait = 100 * time.Millisecond

	// Timeout for blocking operations.
	// Functions fail with FIDO_ERR_RX on timeout.
	fido2DeviceTimeout = 30 * time.Second

	// Operation retry interval.
	// Keep it less frequent than 5Hz / 0.2s.
	fido2RetryInterval = 500 * time.Millisecond

	// Timeout for touch.Status operations.
	// Keep it less frequent than 5Hz / 0.2s.
	fido2TouchMaxWait = 200 * time.Millisecond
)

// User-friendly device filter errors.
var (
	errHasExcludedCredential = errors.New("device already holds a registered credential")
	errNoPasswordless        = errors.New("device not registered for passwordless")
	errNoPlatform            = errors.New("device cannot fulfill platform attachment requirement")
	errNoRK                  = errors.New("device lacks resident key capabilities")
	errNoUV                  = errors.New("device lacks PIN or user verification capabilities necessary to support passwordless")
	errPasswordlessU2F       = errors.New("U2F devices cannot do passwordless")
)

// TouchRequest abstracts *libfido2.TouchRequest for testing.
type TouchRequest interface {
	Status(timeout time.Duration) (touched bool, err error)
	Stop() error
}

// FIDODevice abstracts *libfido2.Device for testing.
type FIDODevice interface {
	// Info mirrors libfido2.Device.Info.
	Info() (*libfido2.DeviceInfo, error)

View on GitHub (pinned to 1283425b60)

Solutions

  1. Use the existing credential — the key is already registered, so just log in instead of registering again.
  2. Delete the old registration first (tsh mfa rm <name>) and then re-register the key.
  3. If you must create a new credential, wipe/reset the YubiKey (with caution: factory reset erases all credentials).
  4. If intentional double registration is desired, drop the existing credential from the excludeCredentials list.

Example fix

// before
cred, err := wancli.Register(ctx, origin, creation, prompt, nil)
// after
if errors.Is(err, errHasExcludedCredential) {
	return nil, trace.AlreadyExists("device already registered; remove old MFA device first")
}
cred, err := wancli.Register(ctx, origin, creation, prompt, nil)
Defensive patterns

Strategy: type-guard

Validate before calling

// before registering, list existing MFA devices and skip registration if the key is present
tsh mfa ls

Type guard

func isExcludedCredentialErr(err error) bool {
	return strings.Contains(err.Error(), "already holds a registered credential") ||
		errors.Is(err, libfido2.ErrUserPresenceRequired)
}

Try / catch

_, err := wancli.Register(ctx, origin, cc, prompt, nil)
if isExcludedCredentialErr(err) {
	return trace.AlreadyExists("device already registered; use it to log in or remove the old device")
}

Prevention

When it happens

Trigger: fido2.go:537 — libfido2.ErrUserPresenceRequired observed by a YubiKey4 when the credential already exists; fido2.go:548 — the device filter detects the device contains a credential from the excludeList during Register.

Common situations: Re-registering a security key that already holds this site's credential (common on YubiKey4, which stores few credentials); running tsh mfa add twice with the same key; idempotent registration attempts.

Related errors


AI-assisted analysis of gravitational/teleport@1283425b60 (2026-09-02). Data as JSON: /api/errors/d3e15a2ade47435c. Report an issue: GitHub.