{"record":{"id":"b31f402685edd6cf","repo":"microsoft/aspire","slug":"connection-string-is-unavailable-postgresbuilderextensions","errorCode":null,"errorMessage":"Connection string is unavailable","messagePattern":"Connection string is unavailable","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"warning","filePath":"src/Aspire.Hosting.PostgreSQL/PostgresBuilderExtensions.cs","lineNumber":100,"sourceCode":"\n            await npgsqlConnection.OpenAsync(ct).ConfigureAwait(false);\n\n            if (npgsqlConnection.State != System.Data.ConnectionState.Open)\n            {\n                throw new InvalidOperationException($\"Could not open connection to '{postgresServer.Name}'\");\n            }\n\n            foreach (var name in postgresServer.Databases.Keys)\n            {\n                if (builder.Resources.FirstOrDefault(n => string.Equals(n.Name, name, StringComparisons.ResourceName)) is PostgresDatabaseResource postgreDatabase)\n                {\n                    await CreateDatabaseAsync(npgsqlConnection, postgreDatabase, @event.Services, ct).ConfigureAwait(false);\n                }\n            }\n        });\n\n        var healthCheckKey = $\"{name}_check\";\n        builder.Services.AddHealthChecks().AddNpgSql(sp => connectionString ?? throw new InvalidOperationException(\"Connection string is unavailable\"), name: healthCheckKey, configure: (connection) =>\n        {\n            // HACK: The Npgsql client defaults to using the username in the connection string if the database is not specified. Here\n            //       we override this default behavior because we are working with a non-database scoped connection string. The Aspirified\n            //       package doesn't have to deal with this because it uses a datasource from DI which doesn't have this issue:\n            //\n            //       https://github.com/npgsql/npgsql/blob/c3b31c393de66a4b03fba0d45708d46a2acb06d2/src/Npgsql/NpgsqlConnection.cs#L445\n            //\n            connection.ConnectionString += \";Database=postgres;\";\n        });\n\n        return builder.AddResource(postgresServer)\n                      .WithEndpoint(port: port, targetPort: 5432, name: PostgresServerResource.PrimaryEndpointName) // Internal port is always 5432.\n                      .WithImage(PostgresContainerImageTags.Image, PostgresContainerImageTags.Tag)\n                      .WithImageRegistry(PostgresContainerImageTags.Registry)\n                      .WithIconName(\"DatabaseMultiple\")\n                      .WithEnvironment(\"POSTGRES_HOST_AUTH_METHOD\", \"scram-sha-256\")\n                      .WithEnvironment(\"POSTGRES_INITDB_ARGS\", \"--auth-host=scram-sha-256 --auth-local=scram-sha-256\")\n                      .WithEnvironment(context =>","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.PostgreSQL/PostgresBuilderExtensions.cs#L82-L118","documentation":"The Npgsql health check registered by AddPostgres resolves its connection string via a factory: connectionString ?? throw new InvalidOperationException(\"Connection string is unavailable\"). If the health check executes before the ConnectionStringAvailableEvent handler cached the value, this exception fails the health check. It is a startup-ordering/state issue, not a Postgres connectivity failure.","triggerScenarios":"Health check runs before the connectionString local is populated by the ConnectionStringAvailableEvent callback, or the event never fired because the resource failed to resolve its connection string.","commonSituations":"Querying health endpoints during AppHost startup; resource start failure preventing connection-string resolution; misconfigured Postgres parameters so the event handler throws first.","solutions":["Let startup complete before relying on health status; check whether the resource actually started.","Fix the connection-string resolution failure (missing username/password parameters or endpoint) surfaced by the earlier event handler.","Bind the health check to the resource's ConnectionStringExpression rather than the cached local."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await healthCheckService.CheckHealthAsync(); } catch (InvalidOperationException ex) when (ex.Message == \"Connection string is unavailable\") { logger.LogWarning(\"Postgres health check ran before connection string resolved; retry after startup.\"); }","preventionTips":["Query health status only after startup completes","Fix connection-string resolution failures reported by the event handler first","Keep default AddPostgres health check wiring; avoid reordering resource startup"],"tags":["aspire","postgresql","health-check","connection-string"],"backgroundTag":"missing-config-value","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"}