{"record":{"id":"ac37ceda33ab067d","repo":"gravitational/teleport","slug":"prompt-returned-invalid-credential-v-ac37ce","errorCode":null,"errorMessage":"prompt returned invalid credential: %#v","messagePattern":"prompt returned invalid credential: %#v","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/auth/webauthncli/prompt.go","lineNumber":175,"sourceCode":"\t\tcred := &CredentialInfo{\n\t\t\tID: []byte(c.CredentialID),\n\t\t\tUser: UserInfo{\n\t\t\t\tUserHandle: c.User.UserHandle,\n\t\t\t\tName:       c.User.Name,\n\t\t\t},\n\t\t}\n\t\tcredMap[cred] = c\n\t\twcreds[i] = cred\n\t}\n\n\twchoice, err := p.impl.PromptCredential(wcreds)\n\tif err != nil {\n\t\treturn nil, trace.Wrap(err)\n\t}\n\n\tchoice, ok := credMap[wchoice]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"prompt returned invalid credential: %#v\", wchoice)\n\t}\n\treturn choice, nil\n}\n","sourceCodeStart":157,"sourceCodeEnd":179,"githubUrl":"https://github.com/gravitational/teleport/blob/1283425b60ec5f60d509ba4c791183d452923ff7/lib/auth/webauthncli/prompt.go#L157-L179","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (front-end returns user-typed raw ID, map is keyed by base64)\nwchoice := userInput.rawCredentialID\nchoice, err := prompt.PromptCredential(creds)\n// after\nwchoice := base64.RawURLEncoding.EncodeToString(userInput.rawCredentialIDBytes)\nchoice, err := prompt.PromptCredential(creds)","handlingStrategy":"validation","validationCode":"wchoice, err := readUserChoice()\nif err != nil { return err }\nif _, ok := credMap[wchoice]; !ok {\n    return fmt.Errorf(\"%q is not one of the offered credentials\", wchoice)\n}","typeGuard":"func isKnownCredentialChoice(credMap map[string]*CredentialInfo, wchoice string) bool {\n    _, ok := credMap[wchoice]\n    return ok\n}","tryCatchPattern":"choice, err := wp.PromptCredential(creds)\nif err != nil {\n    if strings.Contains(err.Error(), \"prompt returned invalid credential\") {\n        // re-show the prompt with the current credential list\n        return wp.PromptCredential(creds)\n    }\n    return nil, trace.Wrap(err)\n}","preventionTips":["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."],"tags":["webauthn","prompt","input-validation"],"backgroundTag":"invalid-picker-selection","analyzedSha":"1283425b60ec5f60d509ba4c791183d452923ff7","analyzedAt":"2026-09-02T04:06:41.601Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}