gravitational/teleport · warning
touch ID not available
Error message
touch ID not available
What it means
ErrNotAvailable is the sentinel error of the touchid package, indicating the platform authenticator (Touch ID) is not usable on the current machine. Every public entry point (Register, Login, ListCredentials, DeleteCredential, Guard, Authenticate) checks IsAvailable() first and returns this error when the check fails. It lets callers degrade gracefully to other MFA methods instead of failing unpredictably deeper in the stack.
Source
Thrown at lib/auth/touchid/api.go:52
"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 different
// functions, provided the functions are invoked in a short time interval.View on GitHub (pinned to 1283425b60)
Solutions
- Check touchid.IsAvailable() before calling any touchid API and fall back to another authenticator (e.g. webauthncli/FIDO2) when false.
- Enroll fingerprints in System Settings > Touch ID & Password on macOS.
- Verify the app/binary is running on real macOS hardware with a Secure Enclave, not a VM or container.
- If MDM blocks biometrics, ask IT to allow Touch ID or use an alternate MFA device.
Example fix
// before
reg, err := touchid.Register(origin, cc)
// after
if !touchid.IsAvailable() {
return mfaFallbackRegister(origin, cc) // e.g. FIDO2 flow
}
reg, err := touchid.Register(origin, cc) Defensive patterns
Strategy: fallback
Validate before calling
if !touchid.IsAvailable() {
// use FIDO2 or another MFA method instead
} Type guard
func available() bool { return touchid.IsAvailable() } Try / catch
reg, err := touchid.Register(origin, cc)
if errors.Is(err, touchid.ErrNotAvailable) {
reg, err = fidoFallbackRegister(origin, cc)
} Prevention
- Always gate touchid API calls behind touchid.IsAvailable().
- Design MFA UX with a non-platform fallback (FIDO2/OTP).
- Test on machines without Touch ID (desktops, VMs) to exercise the fallback path.
When it happens
Trigger: Calling any touchid API (Register at api.go:231, Login at api.go:451, ListCredentials, DeleteCredential, Guard, Authenticate) when IsAvailable() returns false: no Touch ID hardware, unsupported macOS version, or the underlying darwin/CTK API reports the authenticator unavailable.
Common situations: Running Teleport client on Linux/Windows where lib/auth/touchid is compiled but no Touch ID exists; macOS without Touch ID (desktop Macs, VMs); biometrics not enrolled or disabled by MDM/policy; Secure Enclave unavailable.
Related errors
- credential not found
- cannot fulfill authenticator attachment %q
- cannot fulfill credential parameters, only ES256 are support
- cred required for %q ceremony
- picker returned invalid credential: %#v
AI-assisted analysis of gravitational/teleport@1283425b60 (2026-09-02).
Data as JSON: /api/errors/db7ef819bb58888d.
Report an issue: GitHub.