You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Linux store throws TypeInitializationException (not DllNotFoundException) on every call when libsecret is missing, so consumers can't detect it and fall back #168
LinuxSecretServiceCredentialStore builds its schema handle in a static field of a nested class (Storage/LinuxSecretServiceCredentialStore.cs, ~line 157):
On a machine without libsecret-1.so.0 (a headless server, SSH session, or container), the P/Invoke's DllNotFoundException is thrown inside the static initializer. .NET wraps it in a TypeInitializationException, and every later access to Schema throws that same wrapped exception again.
The class remarks (lines 18–19) tell consumers that the provider "will fail at the first operation; consumers should detect this and fall back to InMemoryCredentialStore". But what they receive is a TypeInitializationException whose message is "The type initializer for 'Schema' threw an exception.", not the DllNotFoundException or CredentialStoreException a caller would reasonably catch.
Repro
In a Linux container with no libsecret (ldconfig -p | grep libsecret is empty):
varstore=CredentialStoreFactory.CreateDefault("x");store.TryLoad(...);// System.TypeInitializationException -> DllNotFoundException: Unable to load shared library 'libsecret-1.so.0'store.TryLoad(...);// same TypeInitializationException again
Why it matters
Consumers following the documented "detect and fall back" advice miss this case. For example, OAICLI's Auth.IsMissingSecretStore matches PlatformNotSupportedException or DllNotFoundException or EntryPointNotFoundException, so on exactly the headless-Linux setup that fallback was written for, users get Error: The type initializer for 'Schema' threw an exception. and exit code 255 (tracked on the OAICLI side separately).
Suggested fix
Create the schema lazily inside a method (e.g. a Lazy<IntPtr> or a guarded static getter), not in a type initializer.
Catch DllNotFoundException / EntryPointNotFoundException there and rethrow as CredentialStoreException (or PlatformNotSupportedException) with a message naming libsecret, so there is one documented exception type to catch.
Update the class remarks to name the exception consumers should catch.
Acceptance criteria
Without libsecret, the first and every later operation throw the documented exception type, never a TypeInitializationException.
A test covers the missing-library path, at least by exercising the translation logic.
Next step: build the schema handle lazily in a guarded getter, translate DllNotFoundException / EntryPointNotFoundException into one documented exception (CredentialStoreException or PlatformNotSupportedException), name that exception in the remarks, and test the translation logic.
Activity
matt-edmondson commentedon Sep 27, 2026
Triage
InMemoryCredentialStore" path cannot work, because callers get aTypeInitializationException. This breaks downstream tools today (On Linux without libsecret, commands fail with "The type initializer for 'Schema' threw an exception" instead of the no-secret-store message OAICLI#52), but there is a consumer-side workaround and no data is at risk.LinuxSecretServiceCredentialStore(the staticSchemaclass, ~line 157, and the class remarks). Owner: @matt-edmondsonDllNotFoundException/EntryPointNotFoundExceptioninto one documented exception (CredentialStoreExceptionorPlatformNotSupportedException), name that exception in the remarks, and test the translation logic.Generated by Claude Code