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 not

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Verify the server is reachable: pg_isready -h <host> -p <port>
  2. Check credentials and pg_hba.conf / SSL enforcement for the multica user
  3. If Postgres is still starting (container/k8s), wait for readiness then re-run — the backfill is idempotent
  4. 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

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


AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15). Data as JSON: /api/errors/eb6e7344689f5d21. Report an issue: GitHub.