Description
On headless Linux (Debian 12, aarch64), the MSAL Silent token provider crashes unconditionally with wam_runtime_init_failed before it can enumerate MSAL accounts or read the plain-text token cache at ~/.local/.IdentityService/msal.cache. The exception propagates out of GetAccountsInternalAsync and kills the entire silent auth attempt. The credential provider then falls through to browser (fails — no display) and device code (times out in non-interactive mode), ultimately returning "could not acquire credentials" — even though a valid access token and refresh token are present in the MSAL cache from a prior dotnet restore --interactive run.
Contrast: a second feed in the same NuGet.Config that has a cached entry in SessionTokenCache.dat works immediately — MSAL is never invoked. This confirms the environment and network are not at fault.
Environment (OS/platform or image)
- OS: Debian GNU/Linux 12 (bookworm)
- Architecture: aarch64
- Kernel: 6.12.54-linuxkit
- Environment: Headless devcontainer — no D-Bus user session, no keyring daemon, no display
- Credential provider install:
curl -fsSL https://aka.ms/install-artifacts-credprovider.sh | bash (broker-enabled build, v2.0.2+d0f3d8d)
- MSAL.NET version: 4.77.1.0 (from exception header)
Tool versions
$ dotnet --version
8.0.422
$ dotnet --list-sdks
8.0.422 [/usr/share/dotnet/sdk]
$ dotnet --list-runtimes
Microsoft.AspNetCore.App 8.0.28 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 8.0.28 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
Client/protocol path in use
Dotnet tool invocation
Credential Provider logs
Steps to reproduce
- Install the credential provider via the standard install script (broker-enabled build).
- Authenticate once interactively via
dotnet restore --interactive, completing the device code flow. This populates ~/.local/.IdentityService/msal.cache with a valid access token and refresh token for an Azure DevOps Artifacts feed.
- Subsequently run
dotnet restore (non-interactive) for a feed that has no entry in SessionTokenCache.dat.
- Observe warnings: "Using plain-text fallback token cache" followed by "could not acquire credentials".
To reproduce directly, invoke the credential provider with verbose output:
~/.nuget/plugins/netcore/CredentialProvider.Microsoft/CredentialProvider.Microsoft \
-V Verbose -C \
-U "https://pkgs.dev.azure.com/<org>/_packaging/<feed>/nuget/v3/index.json"
Full -V Verbose output from the direct invocation above. Key sequence:
[Verbose] Could not find cached SessionToken for https://pkgs.dev.azure.com/<org>/...
[Verbose] Found AAD Authority from 401 headers: https://login.windows.net/<tenant>
[Warning] Warning: Cannot persist Microsoft authentication token cache securely!
[Warning] Warning: Using plain-text fallback token cache
[Verbose] VstsCredentialProvider - Attempting to acquire bearer token using provider 'MSAL Silent'
[Verbose] VstsCredentialProvider - Bearer token provider 'MSAL Silent' failed with exception:
MSAL.NetCore.4.77.1.0.MsalClientException:
ErrorCode: wam_runtime_init_failed
Microsoft.Identity.Client.MsalClientException: The type initializer for 'Microsoft.Identity.Client.NativeInterop.API' threw an exception.
---> System.TypeInitializationException: The type initializer for 'Microsoft.Identity.Client.NativeInterop.API' threw an exception.
---> System.PlatformNotSupportedException: Operation is not supported on this platform.
at Microsoft.Identity.Client.NativeInterop.LinuxPlatformUtils.GetPackagePathAndSetEnvironmentVariables()
at Microsoft.Identity.Client.NativeInterop.API..cctor()
at Microsoft.Identity.Client.NativeInterop.Module.AddRef(String handleName)
at Microsoft.Identity.Client.NativeInterop.Core..ctor()
at Microsoft.Identity.Client.Platforms.Features.RuntimeBroker.RuntimeBroker.<>c.<.cctor>b__26_0()
at Microsoft.Identity.Client.Platforms.Features.RuntimeBroker.RuntimeBroker.IsBrokerInstalledAndInvokable(AuthorityType authorityType)
at Microsoft.Identity.Client.ClientApplicationBase.GetAccountsFromBrokerAsync(...)
at Microsoft.Identity.Client.ClientApplicationBase.GetAccountsInternalAsync(...)
at Microsoft.Artifacts.Authentication.MsalSilentTokenProvider.GetTokenAsync(TokenRequest tokenRequest, CancellationToken)
[Verbose] VstsCredentialProvider - Attempting to acquire bearer token using provider 'MSAL Broker Interactive'
[Verbose] VstsCredentialProvider - Bearer token provider 'MSAL Broker Interactive' failed with exception:
(same wam_runtime_init_failed)
[Verbose] VstsCredentialProvider - Attempting to acquire bearer token using provider 'MSAL Interactive'
(linux_xdg_open_failed — no display)
[Verbose] VstsCredentialProvider - Attempting to acquire bearer token using provider 'MSAL Device Code'
(prompt shown, task cancelled — non-interactive context)
[Verbose] VstsCredentialProvider - Could not obtain credentials
[Warning] The plugin credential provider could not acquire credentials.
Additional context
Workaround
Install the brokerless build, which ships without Microsoft.Identity.Client.NativeInterop.dll and does not attempt WAM initialization:
ARCH=$(uname -m | sed 's/aarch64/arm64/;s/x86_64/x64/')
curl -fsSL \
"https://github.com/microsoft/artifacts-credprovider/releases/latest/download/Microsoft.linux-${ARCH}.Brokerless.NuGet.CredentialProvider.tar.gz" \
| tar xz -C "$HOME/.nuget/plugins" --strip-components=3
Note: the default install script (aka.ms/install-artifacts-credprovider.sh) has no flag to select the brokerless build — manual installation is required.
Description
On headless Linux (Debian 12, aarch64), the MSAL Silent token provider crashes unconditionally with
wam_runtime_init_failedbefore it can enumerate MSAL accounts or read the plain-text token cache at~/.local/.IdentityService/msal.cache. The exception propagates out ofGetAccountsInternalAsyncand kills the entire silent auth attempt. The credential provider then falls through to browser (fails — no display) and device code (times out in non-interactive mode), ultimately returning "could not acquire credentials" — even though a valid access token and refresh token are present in the MSAL cache from a priordotnet restore --interactiverun.Contrast: a second feed in the same
NuGet.Configthat has a cached entry inSessionTokenCache.datworks immediately — MSAL is never invoked. This confirms the environment and network are not at fault.Environment (OS/platform or image)
curl -fsSL https://aka.ms/install-artifacts-credprovider.sh | bash(broker-enabled build,v2.0.2+d0f3d8d)Tool versions
Client/protocol path in use
Dotnet tool invocation
Credential Provider logs
Steps to reproduce
dotnet restore --interactive, completing the device code flow. This populates~/.local/.IdentityService/msal.cachewith a valid access token and refresh token for an Azure DevOps Artifacts feed.dotnet restore(non-interactive) for a feed that has no entry inSessionTokenCache.dat.To reproduce directly, invoke the credential provider with verbose output:
Full
-V Verboseoutput from the direct invocation above. Key sequence:Additional context
Workaround
Install the brokerless build, which ships without
Microsoft.Identity.Client.NativeInterop.dlland does not attempt WAM initialization:Note: the default install script (
aka.ms/install-artifacts-credprovider.sh) has no flag to select the brokerless build — manual installation is required.