gravitational/teleport · warning

webauthn error code %v

Error message

webauthn error code %v

What it means

This is the bare fallback branch of getErrorNameOrLastErr in Teleport's Windows WebAuthn wrapper. It fires when a native WebAuthn call fails, webAuthNGetErrorName returns 0 (the code is unrecognized), AND the last Win32 syscall error is exactly 0 — meaning Windows set no syscall error, so the wrapper can only report the raw numeric WebAuthn error code with no name and no OS detail. It indicates the operation failed but neither the API's name table nor GetLastError explains why.

Source

Thrown at lib/auth/webauthnwin/webauthn_windows.go:224

			},
			RawID: credential,
		},
		AttestationResponse: wantypes.AuthenticatorAttestationResponse{
			AuthenticatorResponse: wantypes.AuthenticatorResponse{
				ClientDataJSON: in.jsonEncodedClientData,
			},
			AttestationObject: bytesFromCBytes(out.cbAttestationObject, out.pbAttestationObject),
		},
	}, nil
}

func getErrorNameOrLastErr(in uintptr, lastError error) error {
	ret := webAuthNGetErrorName(in)
	if ret == 0 {
		if lastError != syscall.Errno(0) {
			return fmt.Errorf("webauthn error code %v and syscall err: %v", in, lastError)
		}
		return fmt.Errorf("webauthn error code %v", in)
	}
	errString := windows.UTF16PtrToString((*uint16)(unsafe.Pointer(ret)))
	return fmt.Errorf("webauthn error code %v: %v", in, errString)
}

func isUVPlatformAuthenticatorAvailable() (bool, error) {
	var out bool
	ret, err := webAuthNIsUserVerifyingPlatformAuthenticatorAvailable(&out)
	if err != nil {
		return false, getErrorNameOrLastErr(ret, err)
	}
	return out, nil
}

// bytesFromCBytes gets slice of bytes from C type and copies it to new slice
// so that it won't interfere when main objects is free.
func bytesFromCBytes(size uint32, p *byte) []byte {
	if p == nil {

View on GitHub (pinned to 1283425b60)

Solutions

  1. Decode the numeric code in the message against Microsoft's WebAuthn HRESULT list to identify the failure.
  2. Upgrade Teleport so the error-name table includes the newly mapped code.
  3. Retry the WebAuthn ceremony once — some codes are transient (user presence timeouts).
  4. If reproducible, file an issue with the numeric code so the mapping table can be extended.
  5. Test with a different authenticator (Windows Hello vs USB security key) to isolate the device.

Example fix

// before
err := getErrorNameOrLastErr(code, lastErr) // "webauthn error code 536870943" — no context

// after: give callers a typed, decodable error
if lastError != syscall.Errno(0) {
    return fmt.Errorf("webauthn error code %v and syscall err: %v", in, lastError)
}
return fmt.Errorf("webauthn error code %v (0x%08X): unknown WebAuthn status; see Microsoft WebAuthn HRESULT docs", in, uint32(in))
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight: only attempt the ceremony when the platform authenticator answers cleanly
available, err := isUVPlatformAuthenticatorAvailable()
if err != nil {
    return trace.Wrap(err)
}
if !available {
    return trace.BadParameter("WebAuthn unavailable: connect a security key or enable Windows Hello")
}

Type guard

// Detect the bare-code form: contains a code but no syscall errno
func isBareWebauthnCodeErr(err error) bool {
    if err == nil {
        return false
    }
    msg := err.Error()
    return strings.HasPrefix(msg, "webauthn error code ") && !strings.Contains(msg, "syscall err")
}

Try / catch

resp, err := MakeCredential(ctx, req)
if err != nil {
    if isBareWebauthnCodeErr(err) {
        // unrecognized code with no OS detail — usually transient; retry once
        if resp, err = MakeCredential(ctx, req); err != nil {
            return trace.Wrap(err, "webauthn failed with unmapped code %v; report this code", err)
        }
    }
    return trace.Wrap(err)
}

Prevention

When it happens

Trigger: GetAssertion, MakeCredential, or isUVPlatformAuthenticatorAvailable returning an unmapped WebAuthn result code while GetLastError() is ERROR_SUCCESS (0) — e.g. the platform authenticator reports a generic/vendor HRESULT without recording a Win32 error, or a status code (like a retry/time-out code) that the wrapper's name table simply doesn't cover.

Common situations: Newer or older WebAuthn.dll returning codes not present in Teleport's mapping table; vendor security keys returning proprietary status codes; Windows Hello timing out without a Win32 error; CI/VDI environments with virtualized authenticators returning unusual codes.

Related errors


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