multica-ai/multica · error
ping database: %w
Error message
ping database: %w
What it means
pool.Ping(ctx) failed: the pool was constructed but the first real round-trip to Postgres failed. This is the point where unreachable hosts, refused connections, DNS failures, bad credentials, and cancelled contexts actually surface. The wrapped pg error identifies which of these applies.
Source
Thrown at server/cmd/backfill_task_usage_hourly/main.go:93
if dbURL == "" {
dbURL = "postgres://multica:multica@localhost:5432/multica?sslmode=disable"
}
// SIGINT/SIGTERM cancels ctx so an in-flight slice stops cleanly —
// each slice runs in its own transaction (the window function), so
// Postgres rolls back the interrupted one and the idempotent design
// lets a later run resume from where this one stopped.
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
pool, err := pgxpool.New(ctx, dbURL)
if err != nil {
return fmt.Errorf("connect to database: %w", err)
}
defer pool.Close()
if err := pool.Ping(ctx); err != nil {
return fmt.Errorf("ping database: %w", err)
}
// Serialise against the cron rollup and any other backfill run via
// advisory lock 4246 — the same id the cron entry checks with
// pg_try_advisory_lock. While this backfill holds it, the cron tick
// no-ops instead of racing on task_usage_hourly row locks; a second
// concurrent backfill blocks here until this one finishes. The lock
// is held on a dedicated session connection for the whole run.
lockConn, err := pool.Acquire(ctx)
if err != nil {
return fmt.Errorf("acquire advisory-lock connection: %w", err)
}
defer lockConn.Release()
if _, err := lockConn.Exec(ctx, `SELECT pg_advisory_lock(4246)`); err != nil {
return fmt.Errorf("acquire advisory lock 4246: %w", err)
}
defer func() {
// Unlock on a fresh context so a cancelled ctx (SIGINT) does notView on GitHub (pinned to 2c0912b6ec)
Solutions
- Verify the server is reachable: pg_isready -h <host> -p <port>
- Check credentials and pg_hba.conf / SSL enforcement for the multica user
- If Postgres is still starting (container/k8s), wait for readiness then re-run — the backfill is idempotent
- Ensure the DSN host/port match where Postgres actually listens (docker port mapping, k8s Service)
Example fix
// before: backfill starts immediately, Ping races container startup // after (operator): wait for readiness before running the backfill pg_isready -h localhost -p 5432 && go run ./server/cmd/backfill_task_usage_hourly
Defensive patterns
Strategy: retry
Validate before calling
if err := pool.Ping(ctx); err != nil { /* server not reachable yet */ } Try / catch
if err := pool.Ping(ctx); err != nil {
return fmt.Errorf("ping database: %w", err)
} Prevention
- Gate the command on pg_isready or a readiness probe before starting
- Keep sslmode consistent with the server's host-based auth config
- The backfill is idempotent — safe to simply re-run after fixing connectivity
When it happens
Trigger: Postgres not running on localhost:5432, wrong port, TLS requirements mismatched with sslmode=disable, pg_hba.conf rejecting the multica user, or SIGINT arriving before/during Ping (ctx cancelled).
Common situations: Dev environment without `make dev` / docker compose up for the database; connecting to a containerized Postgres that exposes 5433; k8s service name typo; database container still booting when the backfill starts.
Related errors
- connect to database: %w
- wecom_credentials_unverifiable
- ping database: %w
- acquire advisory-lock connection: %w
- acquire advisory lock 4246: %w
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/eb6e7344689f5d21.
Report an issue: GitHub.