gravitational/teleport · warning
credential not found
Error message
credential not found
What it means
Touch ID credential lookup returns ErrCredentialNotFound when the platform authenticator has no matching credential for the requested user/relying party — e.g. enumerateCredentials returns zero results or pickCredential finds nothing. It is a sentinel error so callers (like tsh) can fall back to another MFA method.
Source
Thrown at lib/auth/touchid/api.go:51
"slices"
"sort"
"sync"
"sync/atomic"
"time"
"github.com/fxamacker/cbor/v2"
"github.com/go-webauthn/webauthn/protocol"
"github.com/go-webauthn/webauthn/protocol/webauthncose"
"github.com/gravitational/trace"
"github.com/gravitational/teleport"
wantypes "github.com/gravitational/teleport/lib/auth/webauthntypes"
"github.com/gravitational/teleport/lib/darwin"
logutils "github.com/gravitational/teleport/lib/utils/log"
)
var (
ErrCredentialNotFound = errors.New("credential not found")
ErrNotAvailable = errors.New("touch ID not available")
// PromptPlatformMessage is the message shown before Touch ID prompts.
PromptPlatformMessage = "Using platform authenticator, follow the OS prompt"
// PromptWriter is the writer used for prompt messages.
PromptWriter io.Writer = os.Stderr
logger = logutils.NewPackageLogger(teleport.ComponentKey, "TouchID")
)
func promptPlatform() {
if PromptPlatformMessage != "" {
fmt.Fprintln(PromptWriter, PromptPlatformMessage)
}
}
// AuthContext is an optional, shared authentication context.
// Allows reusing a single authentication prompt/gesture between differentView on GitHub (pinned to 1283425b60)
Solutions
- Re-register the Touch ID credential (e.g. `tsh mfa add`) for the user.
- Check errors.Is(err, touchid.ErrCredentialNotFound) and fall back to another MFA device or prompt the user to enroll.
- Enumerate available credentials first (list credential infos) and handle the zero-length case explicitly rather than assuming a credential exists.
Example fix
// before
resp, err := touchid.Login(origin, req, user)
if err != nil {
return trace.Wrap(err)
}
// after
resp, err := touchid.Login(origin, req, user)
if errors.Is(err, touchid.ErrCredentialNotFound) {
return fallbackToOtherMFAMethod(ctx) // e.g. prompt for WebAuthn/OTP
}
if err != nil {
return trace.Wrap(err)
} Defensive patterns
Strategy: type-guard
Validate before calling
infos, err := touchid.ListCredentials()
if err != nil || len(infos) == 0 { return errors.New("no Touch ID credentials registered") } Type guard
if errors.Is(err, touchid.ErrCredentialNotFound) { /* no matching Touch ID credential */ } Try / catch
resp, err := touchid.Login(origin, req, user)
if errors.Is(err, touchid.ErrCredentialNotFound) {
return promptOtherMFAMethod(ctx) // OTP/WebAuthn fallback
} Prevention
- Always offer a non-Touch-ID MFA fallback path in CLI prompts.
- Check registered MFA devices (`tsh mfa ls`) before relying on Touch ID.
- Handle macOS credential resets: re-enroll Touch ID after OS upgrades or keychain wipes.
When it happens
Trigger: Calling Login for a user with no registered Touch ID credential, pickCredential when no credential matches the RP/user, or DeleteCredential/DeleteNonInteractive/TestRegister_rollback targeting a nonexistent credential ID.
Common situations: Touch ID credentials deleted at the OS level (System Settings or keychain reset); switching macOS user accounts; running tsh mfa/tsh login before ever registering Touch ID; credential list wiped by macOS updates.
Related errors
- touch ID not available
- cannot fulfill authenticator attachment %q
- cannot fulfill credential parameters, only ES256 are support
- user has only invalid WebAuthn registrations, consider a use
- cred required for %q ceremony
AI-assisted analysis of gravitational/teleport@1283425b60 (2026-09-02).
Data as JSON: /api/errors/0423a0a0db89b801.
Report an issue: GitHub.