microsoft/aspire · error · DistributedApplicationException

ConnectionStringAvailableEvent was published for the

Error message

ConnectionStringAvailableEvent was published for the '{name}' resource but the connection string was null.

What it means

The OnConnectionStringAvailable callback in AddDatabase resolves the resource's ConnectionStringExpression and asserts the result is non-null. This DistributedApplicationException indicates the event fired but the connection string expression still evaluated to null — an internal inconsistency in the resource's connection-string pipeline.

Solutions

  1. Ensure the database resource is created via AddSqlServer(...).AddDatabase(...) and not constructed manually
  2. Check for custom callbacks (OnResourceModified, transformations) that might clear or replace the connection string or parent reference
  3. Verify all Aspire.Hosting.* packages are on the same version
  4. Log the resource's ConnectionStringExpression earlier in the lifecycle to see when it becomes null

Example fix

// before
var db = new SqlServerDatabaseResource("db", cs => null, sqlServerResource);
// after
var db = builder.AddSqlServer("sql").AddDatabase("db");
Defensive patterns

Strategy: try-catch

Validate before calling

var cs = await dbResource.ConnectionStringExpression.GetValueAsync(ct);
if (cs is null)
{
    throw new InvalidOperationException($"'{dbResource.Name}' has no connection string; check parent resource config");
}

Try / catch

try
{
    connectionString = await dbResource.ConnectionStringExpression.GetValueAsync(ct);
}
catch (DistributedApplicationException ex) when (ex.Message.Contains("ConnectionStringAvailableEvent"))
{
    logger.LogError(ex, "Connection string pipeline broken for {Resource}", dbResource.Name);
    throw;
}

Prevention

When it happens

Trigger: ConnectionStringAvailableEvent is published for the SqlServerDatabaseResource but GetValueAsync on its ConnectionStringExpression returns null, e.g. the parent SQL Server resource's endpoint/reference configuration was mutated or the database resource was constructed without a valid parent reference.

Common situations: Custom resource transformations removing or replacing the parent reference or endpoint; building a database resource manually without AddSqlServer; version mismatch between Aspire packages handling connection string events differently.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting.SqlServer/SqlServerBuilderExtensions.cs:146

        builder.Resource.AddDatabase(sqlServerDatabase);

        string? connectionString = null;

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

        return builder.ApplicationBuilder
            .AddResource(sqlServerDatabase)
            .WithIconName("Database")
            .WithHealthCheck(healthCheckKey)
            .OnConnectionStringAvailable(async (sqlServerDatabase, @event, ct) =>
            {
                connectionString = await sqlServerDatabase.ConnectionStringExpression.GetValueAsync(ct).ConfigureAwait(false);

                if (connectionString == null)
                {
                    throw new DistributedApplicationException($"ConnectionStringAvailableEvent was published for the '{name}' resource but the connection string was null.");
                }
            });
    }

    /// <summary>
    /// Adds a named volume for the data folder to a SQL Server resource.
    /// </summary>
    /// <param name="builder">The resource builder.</param>
    /// <param name="name">The name of the volume. Defaults to an auto-generated name based on the application and resource names.</param>
    /// <param name="isReadOnly">A flag that indicates if this is a read-only volume.</param>
    /// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
    /// <ats-returns>The resource builder.</ats-returns>
    [AspireExport]
    public static IResourceBuilder<SqlServerServerResource> WithDataVolume(this IResourceBuilder<SqlServerServerResource> builder, string? name = null, bool isReadOnly = false)
    {
        ArgumentNullException.ThrowIfNull(builder);

        return builder.WithVolume(name ?? VolumeNameGenerator.Generate(builder, "data"), "/var/opt/mssql", isReadOnly);

View on GitHub (pinned to 25830f84bd)