microsoft/garnet · critical · InvalidAzureConfiguration
Cannot use AzureStorage device with both storage-string and
Error message
Cannot use AzureStorage device with both storage-string and storage-service-uri
What it means
InvalidAzureConfiguration thrown during Options.Initialize when the device type is AzureStorage and BOTH AzureStorageConnectionString and AzureStorageServiceUri are non-empty. These two credential mechanisms are mutually exclusive: connection string uses a shared key/account-key, while service URI uses managed identity / token credentials. Supplying both creates ambiguity, so the guard rejects it at startup.
Source
Thrown at libs/host/Configuration/Options.cs:757
public GarnetServerOptions GetServerOptions(ILogger logger = null)
{
var enableStorageTier = EnableStorageTier.GetValueOrDefault();
var enableRevivification = EnableRevivification.GetValueOrDefault();
if (UseNativeDeviceLinux.GetValueOrDefault())
{
logger?.LogWarning("The --use-native-device-linux option is deprecated. Please use --device-type Native instead.");
DeviceType = DeviceType.Native;
}
var deviceType = GetDeviceType(logger);
var useAzureStorage = deviceType == DeviceType.AzureStorage;
if (useAzureStorage && string.IsNullOrEmpty(AzureStorageConnectionString) && string.IsNullOrEmpty(AzureStorageServiceUri))
throw new InvalidAzureConfiguration("Cannot use AzureStorage device without supplying storage-string or storage-service-uri");
if (useAzureStorage && !string.IsNullOrEmpty(AzureStorageConnectionString) && !string.IsNullOrEmpty(AzureStorageServiceUri))
throw new InvalidAzureConfiguration("Cannot use AzureStorage device with both storage-string and storage-service-uri");
var logDir = LogDir;
if (!useAzureStorage && enableStorageTier) logDir = new DirectoryInfo(string.IsNullOrEmpty(logDir) ? "." : logDir).FullName;
var checkpointDir = CheckpointDir;
if (!useAzureStorage) checkpointDir = new DirectoryInfo(string.IsNullOrEmpty(checkpointDir) ? (string.IsNullOrEmpty(logDir) ? "." : logDir) : checkpointDir).FullName;
if (!Format.TryParseAddressList(Address, Port, out var endpoints, out _, ProtectedMode == CommandLineBooleanOption.True)
|| endpoints.Length == 0)
throw new GarnetException($"Invalid endpoint format {Address} {Port}.");
EndPoint[] clusterAnnounceEndpoint = null;
if (ClusterAnnounceIp != null)
{
ClusterAnnouncePort = ClusterAnnouncePort == 0 ? Port : ClusterAnnouncePort;
clusterAnnounceEndpoint = Format.TryCreateEndpoint(ClusterAnnounceIp, ClusterAnnouncePort, tryConnect: false, logger: logger);
if (clusterAnnounceEndpoint == null || !endpoints.Any(endpoint =>
endpoint is IPEndPoint listenEp && clusterAnnounceEndpoint[0] is IPEndPoint announceEp &&
listenEp.Port == announceEp.Port &&View on GitHub (pinned to 951b0fc683)
Solutions
- Remove one of the two: keep AzureStorageConnectionString for shared-key auth, or keep AzureStorageServiceUri for managed identity — not both.
- If migrating to managed identity, delete the storage-string entry from config and environment.
- Audit config overlays/templates to ensure only one credential source is set.
Example fix
// before
options.AzureStorageConnectionString = "DefaultEndpointsProtocol=...";
options.AzureStorageServiceUri = new Uri("https://mystorage.blob.core.windows.net");
// after: keep only one
options.AzureStorageServiceUri = new Uri("https://mystorage.blob.core.windows.net");
// connection string removed Defensive patterns
Strategy: validation
Validate before calling
void ValidateAzureCredentialExclusivity(Options opts)
{
if (!string.IsNullOrEmpty(opts.AzureStorageConnectionString) && !string.IsNullOrEmpty(opts.AzureStorageServiceUri))
throw new InvalidOperationException("Provide either storage-string OR storage-service-uri, not both.");
} Try / catch
try
{
options.Initialize(logger);
}
catch (InvalidAzureConfiguration ex) when (ex.Message.Contains("both storage-string"))
{
logger.LogCritical("Remove one Azure credential source. Only one of storage-string or service-uri is allowed.");
throw;
} Prevention
- During migration from connection-string to managed identity, remove the old credential in the same change.
- Use a config linter that flags mutually-exclusive Azure credential fields.
- Keep base and overlay configs consistent in which credential source they define.
When it happens
Trigger: Setting device-type to AzureStorage and providing both --storage-string and --storage-service-uri simultaneously in the command line, config file, or environment. This commonly happens when migrating from connection-string auth to managed identity without removing the old setting.
Common situations: Migration from connection-string to managed identity where the old storage-string was left in the config; a deployment template that sets both 'just in case'; merging two config sources (base + overlay) each setting a different credential.
Related errors
- Cannot use AzureStorage device without supplying storage-str
- Invalid endpoint format {Address} {Port}.
- Cluster announce endpoint does not match list of listen endp
- Revivification cannot specify both record sizes and in-chain
- Revivification cannot specify both record counts and powerof
AI-assisted analysis of microsoft/garnet@951b0fc683 (2026-08-13).
Data as JSON: /api/errors/d5c9f83270f224ba.
Report an issue: GitHub.