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

  1. 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
  2. Verify the keychain exists with `security list-keychains` and set a default with `security default-keychain ~/Library/Keychains/login.keychain-db`
  3. 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)
  4. 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

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


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)