{"record":{"id":"8219cf02dfe4d685","repo":"microsoft/aspire","slug":"connectionstringavailableevent-was-published-for-the-qdrant","errorCode":null,"errorMessage":"ConnectionStringAvailableEvent was published for the '{qdrant.Name}' resource but the connection string was null.","messagePattern":"ConnectionStringAvailableEvent was published for the '(.+?)' resource but the connection string was null\\.","errorType":"exception","errorClass":"DistributedApplicationException","httpStatus":null,"severity":"critical","filePath":"src/Aspire.Hosting.Qdrant/QdrantBuilderExtensions.cs","lineNumber":57,"sourceCode":"    public static IResourceBuilder<QdrantServerResource> AddQdrant(this IDistributedApplicationBuilder builder,\n        string name,\n        IResourceBuilder<ParameterResource>? apiKey = null,\n        int? grpcPort = null,\n        int? httpPort = null)\n    {\n        ArgumentNullException.ThrowIfNull(builder);\n        ArgumentException.ThrowIfNullOrEmpty(name);\n\n        var apiKeyParameter = apiKey?.Resource ??\n            ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(builder, $\"{name}-Key\", special: false);\n        var qdrant = new QdrantServerResource(name, apiKeyParameter);\n\n        QdrantClient? qdrantClient = null;\n\n        builder.Eventing.Subscribe<ConnectionStringAvailableEvent>(qdrant, async (@event, ct) =>\n        {\n            var connectionString = await qdrant.ConnectionStringExpression.GetValueAsync(ct).ConfigureAwait(false)\n            ?? throw new DistributedApplicationException($\"ConnectionStringAvailableEvent was published for the '{qdrant.Name}' resource but the connection string was null.\");\n\n            qdrantClient = CreateQdrantClient(connectionString);\n        });\n\n        var healthCheckKey = $\"{name}_check\";\n        builder.Services.AddHealthChecks()\n          .Add(new HealthCheckRegistration(\n              healthCheckKey,\n              sp => new QdrantHealthCheck(qdrantClient ?? throw new InvalidOperationException(\"Qdrant Client is unavailable\")),\n              failureStatus: default,\n              tags: default,\n              timeout: default));\n\n        return builder.AddResource(qdrant)\n            .WithImage(QdrantContainerImageTags.Image, QdrantContainerImageTags.Tag)\n            .WithImageRegistry(QdrantContainerImageTags.Registry)\n            .WithIconName(\"DatabaseSearch\")\n            .WithHttpEndpoint(port: grpcPort, targetPort: QdrantPortGrpc, name: QdrantServerResource.PrimaryEndpointName)","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Qdrant/QdrantBuilderExtensions.cs#L39-L75","documentation":"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.","triggerScenarios":"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.","commonSituations":"Custom container configuration stripping endpoints; model transformations or WithConnectionRedirection misapplied to the Qdrant resource; running in environments where the container's endpoint never materializes.","solutions":["Verify the Qdrant container resource is created with AddQdrant and its endpoint configuration is intact.","Check for customizations (annotation removal, endpoint overrides) that cleared ConnectionStringExpression.","Reproduce with AppHost/dashboard logs to see why the connection string callback returned null.","Ensure you did not replace or remove the Qdrant resource after AddQdrant registered the subscriber."],"exampleFix":"// before\nvar qdrant = builder.AddQdrant(\"qdrant\"); // then endpoint stripped by custom code\n// after\nvar qdrant = builder.AddQdrant(\"qdrant\");\n// leave endpoint/connection-string wiring intact; only use documented With* extensions","handlingStrategy":"validation","validationCode":"if (qdrant.Resource is not IResourceWithConnectionString { ConnectionStringExpression: not null })\n    throw new InvalidOperationException(\"Qdrant resource connection string wiring is broken before client setup.\");","typeGuard":"var hasConnString = qdrant.Resource is IResourceWithConnectionString { ConnectionStringExpression: not null };","tryCatchPattern":"try\n{\n    // AppHost startup path that triggers the subscriber\n    await host.StartAsync(ct);\n}\ncatch (DistributedApplicationException ex) when (ex.Message.Contains(\"connection string was null\"))\n{\n    logger.LogError(ex, \"Qdrant connection string could not be resolved.\");\n}","preventionTips":["Create the resource only via AddQdrant and keep its endpoint wiring intact.","Do not apply custom transformations that clear ConnectionStringExpression.","Inspect dashboard resource details to confirm endpoints resolve before expecting a client."],"tags":["csharp","aspire","qdrant","connection-string"],"backgroundTag":"null-argument","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T09:17:21.228Z"}