microsoft/aspire · error · InvalidOperationException
Connection string is unavailable
Error message
Connection string is unavailable
What it means
The Redis health check registered by AddGarnet resolves the connection string lazily from a service provider via the captured connectionString variable. If the health check executes before ConnectionStringAvailableEvent populated it (or after the event resolved null), the factory throws InvalidOperationException 'Connection string is unavailable', so the health check reports failure instead of passing null to the Redis client.
Solutions
- Let the AppHost start normally — the health check typically recovers once ConnectionStringAvailableEvent resolves the value; verify the resource reaches Running.
- If it never resolves, check logs for the related DistributedApplicationException (error 978) indicating the event handler failed.
- Wait for the resource to be healthy before depending on it: use WaitFor(garnet) in dependent resources so consumers don't start before the connection string exists.
- If seen only in unit tests, ensure the test host runs the resource's eventing/health-check pipeline the same way the real AppHost does.
Example fix
// before
var cache = builder.AddRedis("redis");
var api = builder.AddProject<Projects.Api>("api").WithReference(cache);
// after — dependents wait until Garnet's connection string and health check are ready
var cache = builder.AddGarnet("cache");
var api = builder.AddProject<Projects.Api>("api").WithReference(cache).WaitFor(cache); Defensive patterns
Strategy: fallback
Try / catch
builder.Services.AddHealthChecks().AddRedis(sp =>
connectionString ?? throw new InvalidOperationException("Connection string is unavailable"),
name: healthCheckKey);
// Health checks will surface this as an unhealthy status until the event resolves the value. Prevention
- Use WaitFor(garnet) on dependent resources so they start only after the connection string is ready
- Avoid probing resource health before the AppHost finishes resource startup
- Investigate the companion DistributedApplicationException if the value never resolves
- In tests, run the full eventing pipeline rather than instantiating resources in isolation
When it happens
Trigger: Health check for the '{name}_check' registration runs while the local connectionString variable is still null — i.e. health checks probe the Garnet resource before ConnectionStringAvailableEvent has been handled or when the event handler failed to set a value.
Common situations: Dashboard/health probes hitting the resource very early during AppHost startup before the connection string is resolved; a stuck or failed event handler leaving connectionString null; tests creating the resource without the normal eventing pipeline.
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
- Connection string is not initialized.
- Connection string is unavailable
- Connection string is unavailable
- Connection string is unavailable
- Connection string is unavailable
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/904e2afdad454bcf.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.Garnet/GarnetBuilderExtensions.cs:127
// https://github.com/Azure/azure-dev/issues/4848
var passwordParameter = password?.Resource ?? ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(builder, $"{name}-password", special: false);
var garnet = new GarnetResource(name, passwordParameter);
string? connectionString = null;
builder.Eventing.Subscribe<ConnectionStringAvailableEvent>(garnet, async (@event, ct) =>
{
connectionString = await garnet.ConnectionStringExpression.GetValueAsync(ct).ConfigureAwait(false);
if (connectionString == null)
{
throw new DistributedApplicationException($"ConnectionStringAvailableEvent was published for the '{garnet.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(garnet)
.WithEndpoint(port: port, targetPort: 6379, name: GarnetResource.PrimaryEndpointName)
.WithImage(GarnetContainerImageTags.Image, GarnetContainerImageTags.Tag)
.WithImageRegistry(GarnetContainerImageTags.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 (garnet.PasswordParameter is { } password)
{
context.EnvironmentVariables["GARNET_PASSWORD"] = password;
}
})
.WithArgs(context =>
{View on GitHub (pinned to 25830f84bd)