block/buzz · critical · anyhow::Error
DB connection failed
Error message
DB connection failed: {e} What it means
Fatal startup error: Db::new() failed to establish the Postgres connection pool for the event store. The underlying sqlx error is logged as `Failed to connect to Postgres: {e}` before this wrap; because every relay path needs the DB, startup aborts.
Solutions
- Confirm Postgres is reachable with the same URL: psql "$DATABASE_URL" -c 'select 1'
- Fix credentials, host, port, or database name in DATABASE_URL (and BUZZ_READ_DATABASE_URL if set)
- Add a depends_on healthcheck (or init container) so the relay only starts once Postgres accepts connections
- If Postgres reports too many connections, raise max_connections or lower BUZZ_DB_POOL_SIZE
Example fix
# docker-compose: before
services:
relay:
image: buzz-relay
# starts immediately, loses the race with postgres
# after
services:
relay:
image: buzz-relay
depends_on:
postgres:
condition: service_healthy
postgres:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER}"]
interval: 2s
retries: 15 Defensive patterns
Strategy: retry
Validate before calling
# Boot gate before starting the relay: until psql "$DATABASE_URL" -c 'select 1' >/dev/null 2>&1; do echo 'waiting for postgres'; sleep 1 done exec ./buzz-relay
Try / catch
// In a supervisor wrapper: retry the relay process with backoff only for // db-connect failures at boot; config errors (42) must not be retried.
Prevention
- Gate relay startup on a Postgres healthcheck (depends_on: condition: service_healthy)
- Rotate DB credentials via the same pipeline that restarts the relay
- Monitor Postgres connection headroom against BUZZ_DB_POOL_SIZE plus audit/search pools
When it happens
Trigger: DATABASE_URL points at a Postgres that is down, unreachable (network/firewall/DNS), has wrong credentials, or the database does not exist. Also triggered by an SSL/TLS requirement mismatch or Postgres already at max_connections.
Common situations: Docker Compose / Kubernetes starting the relay before Postgres passes its healthcheck; rotated DB password not updated in the secret; DATABASE_URL copied between environments; local dev without `just setup` having run migrations or started the DB.
Related errors
- Audit DB connection failed
- Search DB connection failed
- Community deletion serving fence is unsafe
- Database migration failed
- Failed to backfill pubkey_allowlist (required when…
AI-assisted analysis of block/buzz@ef2aa1ae38 (2026-09-05).
Data as JSON: /api/errors/07986330106b83c1.
Report an issue: GitHub.
Appendix: source
Thrown at crates/buzz-relay/src/main.rs:261
metrics::gauge!("buzz_push_enabled").set(if config.push_enabled { 1.0 } else { 0.0 });
info!(
port = config.metrics_port,
idle_timeout_secs = usage_idle_timeout_secs,
"Prometheus metrics exporter started"
);
let db_config = DbConfig {
database_url: config.database_url.clone(),
read_database_url: config.read_database_url.clone(),
replica_read_max_age_ms: config.replica_read_max_age_ms,
max_connections: config.db_pool_size,
read_max_connections: config.db_read_pool_size,
..DbConfig::default()
}
.with_session_timeouts_from_env();
let db = Db::new(&db_config).await.map_err(|e| {
error!("Failed to connect to Postgres: {e}");
anyhow::anyhow!("DB connection failed: {e}")
})?;
if db.has_read_pool() {
info!("Postgres connected (writer + lazy read replica pool)");
// Reader-down at boot must not crash or block the relay; this warn-only
// ping is the sole boot-time visibility that the replica is unreachable
// (the lazy pool with min_connections=0 dials nothing until first use).
db.spawn_read_pool_boot_ping();
} else {
info!("Postgres connected");
}
let auto_migrate =
buzz_auto_migrate_enabled(std::env::var("BUZZ_AUTO_MIGRATE").ok().as_deref());
if auto_migrate {
db.migrate().await.map_err(|e| {
error!("Failed to run database migrations: {e}");
anyhow::anyhow!("Database migration failed: {e}")
})?;View on GitHub (pinned to ef2aa1ae38)