git-ecosystem/git-credential-manager · error · InteropException
ErrorSecNoSuchKeychain
ErrorSecNoSuchKeychain
Error message
The keychain does not exist.
What it means
Thrown by SecurityFramework.ThrowIfError when a Security.framework call returns errSecNoSuchKeychain (-25294): the referenced keychain does not exist. The library maps this OS status code to a descriptive InteropException so callers can catch keychain availability problems with a typed error. Typically surfaced from the legacy SecKeychain* APIs (e.g. SecKeychainFindGenericPassword or SecKeychainAddGenericPassword in AddOrUpdate) operating on the default keychain.
Solutions
- Create/unlock the default keychain: open Keychain Access (or run `security create-keychain` / `security unlock-keychain`) and ensure a login keychain exists for the user
- Verify the keychain exists with `security list-keychains` and set a default with `security default-keychain ~/Library/Keychains/login.keychain-db`
- If running headless (CI/service user), provision a keychain for that user or switch to a credential store that does not require one (e.g. plaintext store via credential.credentialStore)
- Catch the InteropException with code -25294 and fall back to another ICredentialStore
Example fix
// before
var keychain = new MacOSKeychain();
keychain.AddOrUpdate(service, account, secret); // throws if login keychain missing
// after
try
{
var keychain = new MacOSKeychain();
keychain.AddOrUpdate(service, account, secret);
}
catch (InteropException ex) when (ex.ErrorCode == -25294)
{
// keychain does not exist — fall back to filesystem store
var store = new CredentialStoreFactory().CreateDefault();
}
Defensive patterns
Strategy: try-catch
Validate before calling
using System;
using System.Diagnostics;
static bool DefaultKeychainExists()
{
var psi = new ProcessStartInfo("security", "default-keychain")
{
RedirectStandardOutput = true, UseShellExecute = false
};
using var p = Process.Start(psi);
p.WaitForExit();
return p.ExitCode == 0; // non-zero when no default keychain is set
}
if (!DefaultKeychainExists())
{
// provision a keychain or switch credential store before calling MacOSKeychain
} Try / catch
try
{
keychain.AddOrUpdate(service, account, secret);
}
catch (InteropException ex) when (ex.ErrorCode == -25294) // errSecNoSuchKeychain
{
// Create/unlock the login keychain or fall back to a non-keychain store
}
Prevention
- Verify `security default-keychain` succeeds before headless/keychain-dependent runs
- In CI, pre-create and unlock a keychain (`security create-keychain`, `security unlock-keychain`) or use a non-keychain credential store
- Avoid running as service accounts with no login keychain unless one is provisioned
- Catch error code -25294 explicitly and fall back to file/env-based credential stores
When it happens
Trigger: Any MacOSKeychain operation routed through ThrowIfError with OS status -25294 — e.g. AddOrUpdate's SecKeychainFindGenericPassword/SecKeychainAddGenericPassword calls when the default (login) keychain is missing or the default keychain path cannot be resolved.
Common situations: Login keychain deleted or never created (fresh/headless accounts), keychain locked-and-removed scenarios, running as a service user (e.g. CI, root, or SSH-only accounts) with no login keychain, or ~/Library/Keychains corrupted/reset.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- ErrorSecInvalidKeychain
- ErrorSecAuthFailed
- ErrorSecDuplicateItem
- ErrorSecItemNotFound
- ErrorSecInteractionNotAllowed
AI-assisted analysis of git-ecosystem/git-credential-manager@e8ce762cd0 (2026-09-11).
Data as JSON: /api/errors/9d8de0012814e0bd.
Report an issue: GitHub.
Appendix: source
Thrown at src/Core/Interop/MacOS/Native/SecurityFramework.cs:142
// https://developer.apple.com/documentation/security/1542001-security_framework_result_codes
public const int OK = 0;
public const int ErrorSecNoSuchKeychain = -25294;
public const int ErrorSecInvalidKeychain = -25295;
public const int ErrorSecAuthFailed = -25293;
public const int ErrorSecDuplicateItem = -25299;
public const int ErrorSecItemNotFound = -25300;
public const int ErrorSecInteractionNotAllowed = -25308;
public const int ErrorSecInteractionRequired = -25315;
public const int ErrorSecNoSuchAttr = -25303;
public static void ThrowIfError(int error, string defaultErrorMessage = "Unknown error.")
{
switch (error)
{
case OK:
return;
case ErrorSecNoSuchKeychain:
throw new InteropException("The keychain does not exist.", error);
case ErrorSecInvalidKeychain:
throw new InteropException("The keychain is not valid.", error);
case ErrorSecAuthFailed:
throw new InteropException("Authorization/Authentication failed.", error);
case ErrorSecDuplicateItem:
throw new InteropException("The item already exists.", error);
case ErrorSecItemNotFound:
throw new InteropException("The item cannot be found.", error);
case ErrorSecInteractionNotAllowed:
throw new InteropException("Interaction with the Security Server is not allowed.", error);
case ErrorSecInteractionRequired:
throw new InteropException("User interaction is required.", error);
case ErrorSecNoSuchAttr:
throw new InteropException("The attribute does not exist.", error);
default:
throw new InteropException(defaultErrorMessage, error);
}
}View on GitHub (pinned to e8ce762cd0)