gravitational/teleport · error
no credentials for user %q
Error message
no credentials for user %q
What it means
pickAssertion in the FIDO2 login flow selects which returned assertion to use. When a target username was supplied (user != "") and none of the assertions returned by the security key carry a matching assertion.User.Name, the flow fails with this error rather than guessing. It means the key authenticated but has no credential bound to that specific user account.
Source
Thrown at lib/auth/webauthncli/fido2.go:420
case l == 0:
return nil, errors.New("authenticator returned empty assertions")
// MFA or single account.
// Note that authenticators don't return the user name, display name or icon
// for a single account per RP.
// See the authenticatorGetAssertion response, user member (0x04):
// https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#authenticatorgetassertion-response-structure
case !passwordless, l == 1:
return assertions[0], nil
// Explicit user required. First occurrence wins.
case user != "":
for _, assertion := range assertions {
if assertion.User.Name == user {
return assertion, nil
}
}
return nil, fmt.Errorf("no credentials for user %q", user)
}
// Prepare credentials and show picker.
creds := make([]*CredentialInfo, len(assertions))
credToAssertion := make(map[*CredentialInfo]*libfido2.Assertion)
for i, assertion := range assertions {
cred := &CredentialInfo{
ID: assertion.CredentialID,
User: UserInfo{
UserHandle: assertion.User.ID,
Name: assertion.User.Name,
},
}
credToAssertion[cred] = assertion
creds[i] = cred
}
chosen, err := prompt.PromptCredential(creds)
if err != nil {View on GitHub (pinned to 1283425b60)
Solutions
- Verify the username passed to the login flow exactly matches the one used at registration (case-sensitive).
- List credentials on the device (or let the user pick without a name filter) to see which users the key actually holds.
- Register the user on the current security key with fido2Register before attempting login.
- If the credential was registered with an empty username, call login with an empty user to trigger the credential picker instead of name matching.
Example fix
// before
assertion, err := fido2Login(ctx, cfg, user="Alice", ...) // key has "alice"
// after — match exactly or fall back to picker
if !hasAssertionForUser(assertions, user) {
user = "" // empty user => interactive credential picker
}
assertion, err := fido2Login(ctx, cfg, user, ...) Defensive patterns
Strategy: validation
Validate before calling
creds, err := fido2.ListCredentials(...)
if err != nil { return err }
hasUser := false
for _, c := range creds {
if c.User == user { hasUser = true; break }
}
if !hasUser {
return fmt.Errorf("user %q is not registered on this security key", user)
} Type guard
func keyHasUser(assertions []*libfido2.Assertion, user string) bool {
for _, a := range assertions {
if a.User != nil && a.User.Name == user { return true }
}
return false
} Try / catch
assertion, err := pickAssertion(ctx, cfg, assertions, user, prompt)
if err != nil {
if strings.Contains(err.Error(), "no credentials for user") {
// retry without name filter so the interactive picker runs
return pickAssertion(ctx, cfg, assertions, "", prompt)
}
return trace.Wrap(err)
} Prevention
- Confirm the username matches registration exactly (case-sensitive) before login.
- Register the user on the security key being used.
- Pass an empty user to fall back to the interactive credential picker when unsure which key holds the account.
When it happens
Trigger: Calling login with a specific username against a FIDO2 device that holds credentials for other users (or for which resident credentials for that user do not exist), so all returned assertions have User.Name != user.
Common situations: Typos or different casing in the username; the user's credential was registered on a different security key; the key was registered with an empty/different username (e.g. registered non-discoverable or under another account); after re-imaging or resetting a key that lost resident credentials.
Related errors
- max retry attempts reached: %w
- you are using a security key that is not registered with Tel
- device already holds a registered credential
- device not registered for passwordless
- device cannot fulfill platform attachment requirement
AI-assisted analysis of gravitational/teleport@1283425b60 (2026-09-02).
Data as JSON: /api/errors/d88f820cd7a31205.
Report an issue: GitHub.