gravitational/teleport · error
prompt returned invalid credential: %#v
Error message
prompt returned invalid credential: %#v
What it means
The web prompt implementation (prompt.go) presents credential choices to the user, collects a free-form choice string (wchoice), and maps it back to a *CredentialInfo via a credMap. If the returned string does not correspond to any presented credential, PromptCredential fails with this error rather than returning an unknown credential. It protects the assertion-selection step from bogus prompt output.
Source
Thrown at lib/auth/webauthncli/prompt.go:175
cred := &CredentialInfo{
ID: []byte(c.CredentialID),
User: UserInfo{
UserHandle: c.User.UserHandle,
Name: c.User.Name,
},
}
credMap[cred] = c
wcreds[i] = cred
}
wchoice, err := p.impl.PromptCredential(wcreds)
if err != nil {
return nil, trace.Wrap(err)
}
choice, ok := credMap[wchoice]
if !ok {
return nil, fmt.Errorf("prompt returned invalid credential: %#v", wchoice)
}
return choice, nil
}
View on GitHub (pinned to 1283425b60)
Solutions
- Ensure the prompt's returned string is exactly the key used in credMap (same encoding/case as the presented credential identifiers).
- Regenerate the prompt UI from the same creds slice used to build credMap so the ID sets match.
- If a user submits an unknown/stale ID, re-prompt with the current credential list instead of passing it through.
- Log wchoice and the available keys to spot encoding/format mismatches.
Example fix
// before (front-end returns user-typed raw ID, map is keyed by base64) wchoice := userInput.rawCredentialID choice, err := prompt.PromptCredential(creds) // after wchoice := base64.RawURLEncoding.EncodeToString(userInput.rawCredentialIDBytes) choice, err := prompt.PromptCredential(creds)
Defensive patterns
Strategy: validation
Validate before calling
wchoice, err := readUserChoice()
if err != nil { return err }
if _, ok := credMap[wchoice]; !ok {
return fmt.Errorf("%q is not one of the offered credentials", wchoice)
} Type guard
func isKnownCredentialChoice(credMap map[string]*CredentialInfo, wchoice string) bool {
_, ok := credMap[wchoice]
return ok
} Try / catch
choice, err := wp.PromptCredential(creds)
if err != nil {
if strings.Contains(err.Error(), "prompt returned invalid credential") {
// re-show the prompt with the current credential list
return wp.PromptCredential(creds)
}
return nil, trace.Wrap(err)
} Prevention
- Key the credMap and the prompt UI off the same identifier encoding (e.g. base64 RawURL credential IDs).
- Re-render the picker from the current credential list rather than caching stale IDs client-side.
- Validate user-supplied choice strings against the offered set before returning from the prompt.
When it happens
Trigger: A WebAuthn login with credential picker where the prompt handler returns a choice string that is not one of the offered credential IDs — e.g. the user/UI supplies an arbitrary or stale value, or the map was built from a different credential set than the prompt displayed.
Common situations: Custom web prompts echoing a different identifier format (e.g. raw ID vs base64-encoded ID); front-end code caching an old credential ID; race where the credential list changed between display and submission; test harnesses injecting arbitrary strings.
Related errors
- distinguished name too large, refusing to parse
- credential not found
- touch ID not available
- cannot fulfill credential parameters, only ES256 are support
- user has only invalid WebAuthn registrations, consider a use
AI-assisted analysis of gravitational/teleport@1283425b60 (2026-09-02).
Data as JSON: /api/errors/ac37ceda33ab067d.
Report an issue: GitHub.