microsoft/aspire · critical · DistributedApplicationException

ConnectionStringAvailableEvent was published for the

Error message

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

What it means

When AddQdrant registers the Qdrant resource, it subscribes to ConnectionStringAvailableEvent to build a QdrantClient from the resolved connection string. If qdrant.ConnectionStringExpression evaluates to null when the event fires, it throws DistributedApplicationException instead of creating a client from a null string.

Solutions

  1. Verify the Qdrant container resource is created with AddQdrant and its endpoint configuration is intact.
  2. Check for customizations (annotation removal, endpoint overrides) that cleared ConnectionStringExpression.
  3. Reproduce with AppHost/dashboard logs to see why the connection string callback returned null.
  4. Ensure you did not replace or remove the Qdrant resource after AddQdrant registered the subscriber.

Example fix

// before
var qdrant = builder.AddQdrant("qdrant"); // then endpoint stripped by custom code
// after
var qdrant = builder.AddQdrant("qdrant");
// leave endpoint/connection-string wiring intact; only use documented With* extensions
Defensive patterns

Strategy: validation

Validate before calling

if (qdrant.Resource is not IResourceWithConnectionString { ConnectionStringExpression: not null })
    throw new InvalidOperationException("Qdrant resource connection string wiring is broken before client setup.");

Type guard

var hasConnString = qdrant.Resource is IResourceWithConnectionString { ConnectionStringExpression: not null };

Try / catch

try
{
    // AppHost startup path that triggers the subscriber
    await host.StartAsync(ct);
}
catch (DistributedApplicationException ex) when (ex.Message.Contains("connection string was null"))
{
    logger.LogError(ex, "Qdrant connection string could not be resolved.");
}

Prevention

When it happens

Trigger: The ConnectionStringAvailableEvent publishes for the Qdrant resource but its ConnectionStringExpression yields null — e.g. the underlying container resource's endpoint/connection-string callback is missing or misconfigured.

Common situations: Custom container configuration stripping endpoints; model transformations or WithConnectionRedirection misapplied to the Qdrant resource; running in environments where the container's endpoint never materializes.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting.Qdrant/QdrantBuilderExtensions.cs:57

    public static IResourceBuilder<QdrantServerResource> AddQdrant(this IDistributedApplicationBuilder builder,
        string name,
        IResourceBuilder<ParameterResource>? apiKey = null,
        int? grpcPort = null,
        int? httpPort = null)
    {
        ArgumentNullException.ThrowIfNull(builder);
        ArgumentException.ThrowIfNullOrEmpty(name);

        var apiKeyParameter = apiKey?.Resource ??
            ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(builder, $"{name}-Key", special: false);
        var qdrant = new QdrantServerResource(name, apiKeyParameter);

        QdrantClient? qdrantClient = null;

        builder.Eventing.Subscribe<ConnectionStringAvailableEvent>(qdrant, async (@event, ct) =>
        {
            var connectionString = await qdrant.ConnectionStringExpression.GetValueAsync(ct).ConfigureAwait(false)
            ?? throw new DistributedApplicationException($"ConnectionStringAvailableEvent was published for the '{qdrant.Name}' resource but the connection string was null.");

            qdrantClient = CreateQdrantClient(connectionString);
        });

        var healthCheckKey = $"{name}_check";
        builder.Services.AddHealthChecks()
          .Add(new HealthCheckRegistration(
              healthCheckKey,
              sp => new QdrantHealthCheck(qdrantClient ?? throw new InvalidOperationException("Qdrant Client is unavailable")),
              failureStatus: default,
              tags: default,
              timeout: default));

        return builder.AddResource(qdrant)
            .WithImage(QdrantContainerImageTags.Image, QdrantContainerImageTags.Tag)
            .WithImageRegistry(QdrantContainerImageTags.Registry)
            .WithIconName("DatabaseSearch")
            .WithHttpEndpoint(port: grpcPort, targetPort: QdrantPortGrpc, name: QdrantServerResource.PrimaryEndpointName)

View on GitHub (pinned to 25830f84bd)