gravitational/teleport · error
picker returned invalid credential: %#v
Error message
picker returned invalid credential: %#v
What it means
pickCredential validates that the credential chosen by the native macOS picker (user interaction dialog) actually points at one of the credentials that were offered for selection. Because the picker returns a pointer, it must be an element of the deduplicated candidate slice; anything else would break the credential-to-assertion mapping downstream. This error means the picker implementation returned a pointer outside that slice.
Source
Thrown at lib/auth/touchid/api.go:598
promptOnce()
var choice *CredentialInfo
var choiceErr error
if err := actx.Guard(func() {
choice, choiceErr = picker.PromptCredential(deduped)
}); err != nil {
return nil, trace.Wrap(err)
}
if choiceErr != nil {
return nil, trace.Wrap(choiceErr)
}
// Is choice a pointer within the slice?
// We could work around this requirement, but it seems better to constrain the
// picker API from the start.
if slices.Contains(deduped, choice) {
return choice, nil
}
return nil, fmt.Errorf("picker returned invalid credential: %#v", choice)
}
// ListCredentials lists all registered Secure Enclave credentials.
// Requires user interaction.
func ListCredentials() ([]CredentialInfo, error) {
if !IsAvailable() {
return nil, ErrNotAvailable
}
promptPlatform()
infos, err := native.ListCredentials()
if err != nil {
return nil, trace.Wrap(err)
}
// Parse public keys.
for i := range infos {
info := &infos[i]View on GitHub (pinned to 1283425b60)
Solutions
- Fix the picker implementation to return one of the exact *CredentialInfo pointers it was given, not a copy.
- Ensure the candidate credential slice is not reallocated or rebuilt between showing the picker and reading its result.
- If using a test/stub picker, make it return an element of the slice passed to it (e.g. creds[0]).
- Replace pointer identity matching with credential ID matching if copies are unavoidable (requires code change in pickCredential).
Example fix
// before (stub picker returns a copy)
func (p fakePicker) PromptCredential(creds []*CredentialInfo) (*CredentialInfo, error) {
return &CredentialInfo{ID: creds[0].ID}, nil
}
// after
func (p fakePicker) PromptCredential(creds []*CredentialInfo) (*CredentialInfo, error) {
return creds[0], nil
} Defensive patterns
Strategy: validation
Validate before calling
choice, err := picker.PromptCredential(deduped)
if err == nil && choice != nil && !slices.Contains(deduped, choice) {
return errors.New("picker returned a credential outside the offered set")
} Type guard
func isValidChoice(choices []*CredentialInfo, choice *CredentialInfo) bool {
return choice != nil && slices.Contains(choices, choice)
} Try / catch
cred, err := pickCredential(deduped, picker)
if err != nil {
if strings.Contains(err.Error(), "picker returned invalid credential") {
return nil, trace.BadParameter("picker implementation bug: it must return one of the offered pointers")
}
return nil, trace.Wrap(err)
} Prevention
- Picker implementations must return an element of the input slice verbatim — never a copy.
- Do not rebuild/reallocate the credential slice after handing it to the picker.
- Add a contract test asserting the stub/real picker returns an in-slice pointer.
When it happens
Trigger: During Login, the native picker dialog returns a *CredentialInfo pointer that is not contained in the deduped candidate slice — typically due to a bug or mismatch between the credentials passed to the picker and the value it echoes back.
Common situations: Custom or modified picker implementations (platform-specific code) returning copied/re-allocated CredentialInfo values instead of the original pointers; concurrency bugs where the candidate slice was rebuilt after the picker captured a pointer; test doubles for the picker returning fresh objects.
Related errors
- credential not found
- touch ID not available
- cannot fulfill authenticator attachment %q
- %v: %v
- %v: status %d
AI-assisted analysis of gravitational/teleport@1283425b60 (2026-09-02).
Data as JSON: /api/errors/296620dcd10dee43.
Report an issue: GitHub.