{"record":{"id":"464dd79ae1b243e9","repo":"microsoft/aspire","slug":"connection-string-is-unavailable-kafkabuilderextensions","errorCode":null,"errorMessage":"Connection string is unavailable","messagePattern":"Connection string is unavailable","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Kafka/KafkaBuilderExtensions.cs","lineNumber":62,"sourceCode":"        {\n            connectionString = await kafka.ConnectionStringExpression.GetValueAsync(ct).ConfigureAwait(false);\n\n            if (connectionString == null)\n            {\n                throw new DistributedApplicationException($\"ConnectionStringAvailableEvent was published for the '{kafka.Name}' resource but the connection string was null.\");\n            }\n        });\n\n        var healthCheckKey = $\"{name}_check\";\n\n        // DI must own the check so its producer is reused and disposed with the AppHost.\n        // Key it per resource to avoid sharing the last resource's connection string:\n        // https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks/issues/2298\n        builder.Services.AddKeyedSingleton<KafkaHealthCheck>(healthCheckKey, (sp, _) =>\n        {\n            var options = new KafkaHealthCheckOptions();\n            options.Configuration = new ProducerConfig();\n            options.Configuration.BootstrapServers = connectionString ?? throw new InvalidOperationException(\"Connection string is unavailable\");\n            return new KafkaHealthCheck(options);\n        });\n\n        var healthCheckRegistration = new HealthCheckRegistration(\n            healthCheckKey,\n            sp => sp.GetRequiredKeyedService<KafkaHealthCheck>(healthCheckKey),\n            failureStatus: default,\n            tags: default);\n        builder.Services.AddHealthChecks().Add(healthCheckRegistration);\n\n        return builder.AddResource(kafka)\n            .WithEndpoint(targetPort: KafkaBrokerPort, port: port, name: KafkaServerResource.PrimaryEndpointName)\n            .WithEndpoint(targetPort: KafkaInternalBrokerPort, name: KafkaServerResource.InternalEndpointName)\n            .WithImage(KafkaContainerImageTags.Image, KafkaContainerImageTags.Tag)\n            .WithImageRegistry(KafkaContainerImageTags.Registry)\n            .WithIconName(\"MailMultiple\")\n            .WithEnvironment(context => ConfigureKafkaContainer(context, kafka))\n            .WithHealthCheck(healthCheckKey);","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Kafka/KafkaBuilderExtensions.cs#L44-L80","documentation":"The Kafka health check factory builds a Kafka ProducerConfig from the resource's resolved connection string. If the connection string is null at the time the health check is registered, Aspire throws this InvalidOperationException because a Kafka health check cannot probe a broker without bootstrap servers. It guards against registering a health check with unusable configuration.","triggerScenarios":"Calling AddKafka on a builder whose Kafka resource has no connection string available at registration time — e.g. a resource added without WithReference or without a completed connection-string callback, or passing connectionString: null explicitly.","commonSituations":"Developers call AddKafka on a Kafka server resource before its connection string has been computed (runs before the resource is fully configured), or re-use a connection-string retrieval that returns null when the resource has no endpoint bindings yet.","solutions":["Ensure the Kafka resource has a valid connection string (e.g. it was created via AddKafka and has endpoints registered) before calling AddKafka's health check registration path.","If you pass an explicit connection string, verify it is not null/empty at the call site.","Run the app model after resource building completes so GetValueAsync of the connection string has a resolved value.","If using a custom resource wrapper, implement IResourceWithConnectionString correctly so the connection-string callback returns a non-null expression."],"exampleFix":"// before\nbuilder.AddKafka(\"kafka\", connectionString: null);\n\n// after\nvar kafka = builder.AddKafka(\"kafka\");\nkafka.WithHealthCheck(); // connection string resolved from the resource model","handlingStrategy":"validation","validationCode":"var cs = resource.GetConnectionStringAsync(cts.Token).Result; // or await\nif (string.IsNullOrEmpty(cs)) throw new InvalidOperationException(\"Kafka resource has no connection string before health check registration\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always create Kafka resources through AddKafka so endpoints and connection strings are wired.","Never pass a possibly-null connection string explicitly.","Register health checks after resource configuration is complete."],"tags":["kafka","connection-string","health-check","aspire"],"backgroundTag":"missing-required-config","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}