microsoft/aspire · error · InvalidOperationException

Connection string is unavailable

Error message

Connection string is unavailable

What it means

AddMySql registers a health check whose factory reads the captured connectionString closure; if the health check runs before the ConnectionStringAvailableEvent handler has populated it, the factory throws this InvalidOperationException so the health check reports failure rather than silently using a null connection string.

Solutions

  1. Let the built-in health check gating work: the check failing is transient; ensure something waits on the resource's health before starting dependents.
  2. If writing custom checks, guard against null and return unhealthy instead of throwing.
  3. Investigate why the connection string event hasn't fired (resource configuration) rather than working around the check.
Defensive patterns

Strategy: fallback

Validate before calling

if (connectionString is null) return HealthCheckResult.Unhealthy("Connection string not yet available");

Prevention

When it happens

Trigger: Health check executes before connectionString is assigned — the health check for '{name}_check' runs while the resource's connection string is still unresolved.

Common situations: Startup ordering where health checks execute before the connection-string event; extremely fast app startup against a slow event pipeline; custom lifecycles that delay ConnectionStringAvailableEvent.

Understand the failure class

Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/e41c08f68cf80a13. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.MySql/MySqlBuilderExtensions.cs:79

                throw new DistributedApplicationException($"ResourceReadyEvent was published for the '{resource.Name}' resource but the connection string was null.");
            }

            using var sqlConnection = new MySqlConnection(connectionString);
            await sqlConnection.OpenAsync(ct).ConfigureAwait(false);

            if (sqlConnection.State != System.Data.ConnectionState.Open)
            {
                throw new InvalidOperationException($"Could not open connection to '{resource.Name}'");
            }

            foreach (var sqlDatabase in resource.DatabaseResources)
            {
                await CreateDatabaseAsync(sqlConnection, sqlDatabase, @event.Services, ct).ConfigureAwait(false);
            }
        });

        var healthCheckKey = $"{name}_check";
        builder.Services.AddHealthChecks().AddMySql(sp => connectionString ?? throw new InvalidOperationException("Connection string is unavailable"), name: healthCheckKey);

        return builder.AddResource(resource)
                      .WithEndpoint(port: port, targetPort: 3306, name: MySqlServerResource.PrimaryEndpointName) // Internal port is always 3306.
                      .WithImage(MySqlContainerImageTags.Image, MySqlContainerImageTags.Tag)
                      .WithImageRegistry(MySqlContainerImageTags.Registry)
                      .WithIconName("DatabaseMultiple")
                      .WithEnvironment(context =>
                      {
                          context.EnvironmentVariables[PasswordEnvVarName] = resource.PasswordParameter;
                      })
                      .WithHealthCheck(healthCheckKey);
    }

    /// <summary>
    /// Adds a MySQL database to the application model.
    /// </summary>
    /// <param name="builder">The MySQL server resource builder.</param>
    /// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>

View on GitHub (pinned to 25830f84bd)