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

  1. Remove one of the two: keep AzureStorageConnectionString for shared-key auth, or keep AzureStorageServiceUri for managed identity — not both.
  2. If migrating to managed identity, delete the storage-string entry from config and environment.
  3. 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

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


AI-assisted analysis of microsoft/garnet@951b0fc683 (2026-08-13). Data as JSON: /api/errors/d5c9f83270f224ba. Report an issue: GitHub.