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

  1. Confirm Postgres is reachable with the same URL: psql "$DATABASE_URL" -c 'select 1'
  2. Fix credentials, host, port, or database name in DATABASE_URL (and BUZZ_READ_DATABASE_URL if set)
  3. Add a depends_on healthcheck (or init container) so the relay only starts once Postgres accepts connections
  4. 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

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


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)