microsoft/aspire · error · InvalidOperationException

Connection string is unavailable

Error message

Connection string is unavailable

What it means

AddValkey registers a Redis health check whose factory lazily reads the captured connectionString variable. If the health check runs before the ConnectionStringAvailableEvent handler populated it, the factory throws this InvalidOperationException instead of silently failing health checks.

Solutions

  1. Ensure the Valkey resource starts successfully; check dashboard/logs for resource startup errors so the connection string event fires.
  2. Wait for the resource to reach Running state (or use WaitFor on dependents) before invoking health checks.
  3. In tests, await app.ResourceNotifications.WaitForResourceHealthyAsync("cache") before probing health endpoints.
  4. If the error persists, verify no custom code is suppressing the ConnectionStringAvailableEvent subscription.

Example fix

// before (test)
var response = await client.GetAsync("/health");
// after
await app.ResourceNotifications.WaitForResourceHealthyAsync("cache");
var response = await client.GetAsync("/health");
Defensive patterns

Strategy: retry

Validate before calling

await app.ResourceNotifications.WaitForResourceHealthyAsync("cache"); // before hitting health endpoints

Try / catch

try { var rsp = await client.GetAsync("/health"); rsp.EnsureSuccessStatusCode(); }
catch (InvalidOperationException ex) when (ex.Message == "Connection string is unavailable")
{
    // resource not started yet; wait and retry
}

Prevention

When it happens

Trigger: Health check executes (e.g. during app start or a /health request) while connectionString is still null — the ConnectionStringAvailableEvent either never fired or fired after the health check was invoked.

Common situations: Health checks polled very early at startup; the Valkey resource failed to start so the event never fired; tests hitting the health endpoint before resources are started; resource in error state blocking connection string availability.

Understand the failure class

Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting.Valkey/ValkeyBuilderExtensions.cs:142

        var passwordParameter = password?.Resource ?? ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(builder, $"{name}-password", special: false);

        var valkey = new ValkeyResource(name, passwordParameter);

        string? connectionString = null;

        builder.Eventing.Subscribe<ConnectionStringAvailableEvent>(valkey, async (@event, ct) =>
        {
            connectionString = await valkey.ConnectionStringExpression.GetValueAsync(ct).ConfigureAwait(false);

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

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

        return builder.AddResource(valkey)
            .WithEndpoint(port: port, targetPort: 6379, name: ValkeyResource.PrimaryEndpointName)
            .WithImage(ValkeyContainerImageTags.Image, ValkeyContainerImageTags.Tag)
            .WithImageRegistry(ValkeyContainerImageTags.Registry)
            .WithIconName("Database")
            .WithHealthCheck(healthCheckKey)
            // see https://github.com/microsoft/aspire/issues/3838 for why the password is passed this way
            .WithEntrypoint("/bin/sh")
            .WithEnvironment(context =>
            {
                if (valkey.PasswordParameter is { } password)
                {
                    context.EnvironmentVariables["VALKEY_PASSWORD"] = password;
                }
            })
            .WithArgs(context =>
            {

View on GitHub (pinned to 25830f84bd)