git-ecosystem/git-credential-manager · error · InteropException
ErrorSecItemNotFound
ErrorSecItemNotFound
Error message
The item cannot be found.
What it means
InteropException thrown by SecurityFramework.ThrowIfError when the macOS Security framework returns errSecItemNotFound (-25300). It means a query (SecItemCopyMatching, SecKeychainFindGenericPassword, SecKeychainItemCopyFromPersistentReference) matched no keychain item for the given service/account/persistent reference. This is the keychain equivalent of 'record not found', not a system failure.
Solutions
- Verify the item exists (Keychain Access or `security find-generic-password -s <service>`) and that service/account strings match exactly.
- Store the item first if missing, or handle not-found as a normal 'no credential yet' case rather than an unexpected failure.
- Ensure you are querying the same keychain the item was created in (pass the explicit keychain ref, not null/default).
- If using a persistent reference, re-acquire it from a fresh SecKeychainItemCopyFromPersistentReference-capable source; recreate the item and store a new reference if it is stale.
- Normalize service/account strings (trim, consistent casing) before both storing and querying.
Example fix
// before: throwing away the not-found case as fatal
err = SecKeychainFindGenericPassword(null, serviceLength, service, accountLength, account, out length, out data, IntPtr.Zero);
SecurityFramework.ThrowIfError(err); // InteropException -25300 when nothing stored yet
// after: treat not-found as 'no credential stored yet'
err = SecKeychainFindGenericPassword(null, serviceLength, service, accountLength, account, out length, out data, IntPtr.Zero);
if (err == ErrorSecItemNotFound)
{
credential = ProvisionNewCredential(); // store it via SecKeychainAddGenericPassword
}
else
{
SecurityFramework.ThrowIfError(err);
credential = ReadCredential(data, length);
} Defensive patterns
Strategy: try-catch
Validate before calling
// Probe existence before reading the secret int err = SecKeychainFindGenericPassword(null, service.Length, service, account.Length, account, out _, out IntPtr _, out IntPtr _); bool credentialStored = err == OK; // -25300 means nothing stored yet under that service/account if (!credentialStored) ProvisionCredential();
Type guard
static bool IsSecItemNotFound(InteropException ex) => ex.ErrorCode == -25300; // errSecItemNotFound
Try / catch
try
{
credential = ReadCredentialFromKeychain(service, account);
}
catch (InteropException ex) when (ex.ErrorCode == -25300)
{
// No credential stored yet — normal first-run case.
credential = ProvisionAndStoreCredential(service, account);
} Prevention
- Standardize and normalize service/account strings (trim, exact casing) at a single write/read boundary.
- Check item existence with Keychain Access or `security find-generic-password -s <service>` when debugging.
- Persist keychain persistent references alongside a validity check; refresh them after keychain resets or migrations.
- Query the same keychain the item was written to (pass the explicit keychain ref rather than relying on defaults).
- Treat not-found as a first-run flow, not a crash: always have a provisioning path.
When it happens
Trigger: SecKeychainFindGenericPassword with a service/account string that was never stored (or stored under different casing/whitespace); SecItemCopyMatching whose query dictionary matches zero items; SecKeychainItemCopyFromPersistentReference given a stale persistent reference from an item that was deleted or from a different keychain.
Common situations: Querying a credential before the code path that stores it ever ran; the item was created in the login keychain but the app now targets a different (custom/Shared) keychain; typos or trimming differences in the service name; the user deleted the item via Keychain Access; restoring a persistent reference after a keychain reset or macOS migration.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- ErrorSecNoSuchKeychain
- ErrorSecInvalidKeychain
- ErrorSecAuthFailed
- ErrorSecDuplicateItem
- ErrorSecInteractionNotAllowed
AI-assisted analysis of git-ecosystem/git-credential-manager@e8ce762cd0 (2026-09-11).
Data as JSON: /api/errors/bbcdc324d1cae9d7.
Report an issue: GitHub.
Appendix: source
Thrown at src/Core/Interop/MacOS/Native/SecurityFramework.cs:150
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);
}
}
}
[Flags]
public enum SessionAttributeBits
{
SessionIsRoot = 0x0001,
SessionHasGraphicAccess = 0x0010,
SessionHasTty = 0x0020,View on GitHub (pinned to e8ce762cd0)