git-ecosystem/git-credential-manager · error · InteropException

-1

-1

Error message

Unknown keychain search result type CFTypeID: {typeId}.

What it means

Thrown by MacOSKeychain.GetAccounts after SecItemCopyMatching returns success but the result object is not a CFArray, which is the only type the account-listing path can process. The message embeds the unexpected CoreFoundation type ID. Because the format string uses interpolation of the raw typeId the message may literally read 'CFTypeID: {typeId}' — the code indicates an unexpected/unknown result shape from the Security framework.

Solutions

  1. Update Git Credential Manager to a version that handles single-dictionary (CFDictionary) results in GetAccounts, not just CFArray
  2. Check the macOS version; on macOS versions with changed SecItemCopyMatching semantics, wrap the call and normalize a returned CFDictionary into a single-element list
  3. Reproduce with a minimal SecItemCopyMatching query to log CFGetTypeID(result) and confirm what the framework returns on your OS
  4. Report the CFTypeID value to the library maintainers with macOS version so the type can be mapped

Example fix

// before
if (typeId == CFArrayGetTypeID()) { ... }
throw new InteropException($"Unknown keychain search result type CFTypeID: {typeId}.", -1);
// after
if (typeId == CFArrayGetTypeID()) { ... }
else if (typeId == CFDictionaryGetTypeID())
{
    // single result returned as a dictionary, not wrapped in an array
    string account = GetStringAttribute(resultPtr, kSecAttrAccount);
    return string.IsNullOrEmpty(account) ? new List<string>() : new List<string> { account };
}
throw new InteropException($"Unknown keychain search result type CFTypeID: {typeId}.", -1);
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check the macOS version against known-supported range before using keychain accounts
using System;

static bool KeychainAccountsSupported()
{
    // SecItemCopyMatching result-shape changed on newer macOS; require tested version
    var v = Environment.OSVersion.Version;
    return v.Major >= 10 && v.Minor >= 12;
}

Try / catch

try
{
    IList<string> accounts = keychain.GetAccounts(service);
}
catch (InteropException ex) when (ex.Message.Contains("Unknown keychain search result type CFTypeID"))
{
    // Unexpected CFType returned; treat as empty account list or upgrade GCM
    accounts = Array.Empty<string>();
}

Prevention

When it happens

Trigger: SecItemCopyMatching with kSecMatchLimitAll + kSecReturnAttributes returns OK but hands back a non-CFArray CFType (e.g. a CFDictionary on some macOS versions that return a single item instead of an array).

Common situations: macOS version differences in Security.framework result shapes, newer macOS deprecating legacy keychain APIs and changing SecItemCopyMatching return semantics, or corrupted/unusual keychain items causing a single-result return where an array is expected.

Related errors


AI-assisted analysis of git-ecosystem/git-credential-manager@e8ce762cd0 (2026-09-11). Data as JSON: /api/errors/084433a1c95cbbf3. Report an issue: GitHub.

Appendix: source

Thrown at src/Core/Interop/MacOS/MacOSKeychain.cs:82

                {
                    case OK:
                        int typeId = CFGetTypeID(resultPtr);
                        Debug.Assert(typeId == CFArrayGetTypeID(), "Returned unknown item from account query");
                        if (typeId == CFArrayGetTypeID())
                        {
                            int len = (int)CFArrayGetCount(resultPtr);
                            var accounts = new HashSet<string>(len);
                            for (int i = 0; i < len; i++)
                            {
                                IntPtr dict = CFArrayGetValueAtIndex(resultPtr, i);
                                string account = GetStringAttribute(dict, kSecAttrAccount);
                                accounts.Add(account);
                            }

                            return accounts.ToList();
                        }

                        throw new InteropException($"Unknown keychain search result type CFTypeID: {typeId}.", -1);

                    case ErrorSecItemNotFound:
                        return Array.Empty<string>();

                    default:
                        ThrowIfError(searchResult);
                        return null;
                }
            }
            finally
            {
                if (query != IntPtr.Zero) CFRelease(query);
                if (servicePtr != IntPtr.Zero) CFRelease(servicePtr);
                if (accountPtr != IntPtr.Zero) CFRelease(accountPtr);
                if (resultPtr != IntPtr.Zero) CFRelease(resultPtr);
            }
        }

View on GitHub (pinned to e8ce762cd0)