{"record":{"id":"70efb84a0fb28d08","repo":"microsoft/aspire","slug":"connectionstringavailableevent-was-published-for-the-redis","errorCode":null,"errorMessage":"ConnectionStringAvailableEvent was published for the '{redis.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":"error","filePath":"src/Aspire.Hosting.Redis/RedisBuilderExtensions.cs","lineNumber":88,"sourceCode":"        ArgumentNullException.ThrowIfNull(builder);\n        ArgumentNullException.ThrowIfNull(name);\n\n        // StackExchange.Redis doesn't support passwords with commas.\n        // See https://github.com/StackExchange/StackExchange.Redis/issues/680 and\n        // https://github.com/Azure/azure-dev/issues/4848\n        var passwordParameter = password?.Resource ?? ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(builder, $\"{name}-password\", special: false);\n\n        var redis = new RedisResource(name, passwordParameter);\n\n        string? connectionString = null;\n\n        builder.Eventing.Subscribe<ConnectionStringAvailableEvent>(redis, async (@event, ct) =>\n        {\n            connectionString = await redis.GetConnectionStringAsync(ct).ConfigureAwait(false);\n\n            if (connectionString == null)\n            {\n                throw new DistributedApplicationException($\"ConnectionStringAvailableEvent was published for the '{redis.Name}' resource but the connection string was null.\");\n            }\n        });\n\n        var healthCheckKey = $\"{name}_check\";\n        builder.Services.AddHealthChecks().AddRedis(sp => connectionString ?? throw new InvalidOperationException(\"Connection string is unavailable\"), name: healthCheckKey);\n\n        var redisBuilder = builder.AddResource(redis)\n            .WithEndpoint(port: port, targetPort: 6379, name: RedisResource.PrimaryEndpointName, scheme: RedisResource.StandardRedisScheme)\n            .WithImage(RedisContainerImageTags.Image, RedisContainerImageTags.Tag)\n            .WithImageRegistry(RedisContainerImageTags.Registry)\n            .WithIconName(\"Database\")\n            .WithHealthCheck(healthCheckKey)\n            // see https://github.com/microsoft/aspire/issues/3838 for why the password is passed this way\n            .WithEntrypoint(\"/bin/sh\")\n            .WithEnvironment(context =>\n            {\n                if (redis.PasswordParameter is { } password)\n                {","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Redis/RedisBuilderExtensions.cs#L70-L106","documentation":"When a Redis resource's ConnectionStringAvailableEvent fires, AddRedis retrieves the connection string and expects it to be non-null. If it is still null, an internal invariant of the eventing lifecycle is broken (the event should only publish once the connection string exists), so Aspire throws a DistributedApplicationException immediately rather than propagating a null downstream.","triggerScenarios":"Subscribing to ConnectionStringAvailableEvent for a RedisResource where redis.GetConnectionStringAsync(ct) returns null — typically when the resource has no endpoint/reference that yields a connection string at event time.","commonSituations":"Custom configurations that removed or renamed the primary endpoint, derived resources overriding connection string generation to return null, or hosting scenarios where the event fires before the connection string is set.","solutions":["Inspect why the Redis resource has no connection string: ensure the primary endpoint annotation is intact and hasn't been removed.","Avoid removing endpoints/annotations from the RedisResource via builder APIs that alter connection string generation.","If using a custom derived resource, ensure GetConnectionStringAsync returns a valid value before the event can publish."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Cannot be checked by the caller before the event; ensure the Redis resource is configured with its primary endpoint before running the app host.","typeGuard":null,"tryCatchPattern":"try { await distributedApplication.StartAsync(); } catch (DistributedApplicationException ex) when (ex.Message.Contains(\"ConnectionStringAvailableEvent\") && ex.Message.Contains(\"was null\")) { // inspect resource configuration: connection string generation returned null }","preventionTips":["Do not remove or rename the Redis primary endpoint via WithEndpoint/annotation manipulation.","If subclassing RedisResource, ensure GetConnectionStringAsync never returns null once endpoints exist.","Keep the Redis builder usage stock (AddRedis) unless you understand the eventing lifecycle."],"tags":["redis","connection-string","eventing","aspire"],"backgroundTag":"internal-invariant-violation","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"}