microsoft/ailab · error · InvalidOperationException

The storage account connectionstring is not valid.

Error message

The storage account connectionstring is not valid.

What it means

UploadManager.InitializeContainerAsync reads the Azure Blob connection string from configuration (Data:AzureBlobConnection) and calls CloudStorageAccount.Parse during startup; this validation guard fires when that string cannot be parsed into a valid storage account — i.e. the configuration key is missing, empty, or malformed, so no blob container can be initialized for uploads.

Solutions

  1. Fix the Data:AzureBlobConnection value in appsettings.json/environment to a full 'DefaultEndpointsProtocol=...;AccountName=...;AccountKey=...' connection string
  2. Use CloudStorageAccount.TryParse and fail fast with a clear startup message when configuration is absent
  3. Validate configuration at application start (IStartupFilter or options validation) so misconfiguration is caught before uploads are attempted
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at VirtualStage/Speaker.Recorder/Speaker.Recorder/Services/UploadManager.cs:50 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of microsoft/ailab@89fe2fc620 (2026-09-13). Data as JSON: /api/errors/a2c477ea3da168cd. Report an issue: GitHub.

Appendix: source

Thrown at VirtualStage/Speaker.Recorder/Speaker.Recorder/Services/UploadManager.cs:50

            this.disposeCancellation = new CancellationTokenSource();
            this.StorageConnectionString = configuration.GetValue<string>("Data:AzureBlobConnection");
            this.GlobalIdentifier = identificationService.GetSanitizedIdentifier();
            this.logger = logger;
            var connections = configuration.GetValue("Data:DefaultConnectionLimit", Environment.ProcessorCount - 2);
            ServicePointManager.DefaultConnectionLimit = Math.Max(connections, 1);

            this.uploadRetries = configuration.GetValue("Data:UploadRetries", 10);

            this.cloudBlobContainerTask = this.InitializeContainerAsync();
        }

        private async Task<CloudBlobContainer> InitializeContainerAsync()
        {
            if (string.IsNullOrEmpty(this.StorageConnectionString) || !CloudStorageAccount.TryParse(this.StorageConnectionString, out var account))
            {
                this.IsUploadAvailable = false;
                this.logger.LogError($"The storage account connectionstring is not valid.");
                throw new InvalidOperationException("The storage account connectionstring is not valid.");
            }

            this.IsUploadAvailable = true;
            this.logger.LogInformation($"Initializing Cloud storage for {GlobalIdentifier} in {account.BlobEndpoint}");
            CloudBlobClient blobClient = account.CreateCloudBlobClient();
            blobClient.DefaultRequestOptions.MaximumExecutionTime = TimeSpan.FromSeconds(10);
            blobClient.DefaultRequestOptions.ServerTimeout = TimeSpan.FromSeconds(10);
            CloudBlobContainer blobContainer = blobClient.GetContainerReference(GlobalIdentifier);
            if (await blobContainer.CreateIfNotExistsAsync().ConfigureAwait(false))
            {
                this.logger.LogInformation($"The Cloud storage for {GlobalIdentifier} did not exists and was created");
            }
            return blobContainer;
        }

        public bool ExistsUploadFile(Session session)
        {
            var journalFile = new FileInfo(this.GetJournalFileForSession(session.LocalRecordingFolderPath));

View on GitHub (pinned to 89fe2fc620)