payloadcms/payload · critical · Error
Error: cannot connect to Postgres: ${err.message}
Error message
Error: cannot connect to Postgres: ${err.message} What it means
Thrown by the Postgres (db-postgres) adapter's `connect` after the underlying connection attempt rejects. The adapter logs the detail, calls `rejectInitializing` to fail the init promise, then re-throws a wrapped Error so that `payload.init()` rejects and the app fails fast rather than running without a DB.
Source
Thrown at packages/db-postgres/src/connect.ts:113
`${err.message.charAt(0).toUpperCase() + err.message.slice(1)}, creating...`,
)
const isCreated = await this.createDatabase()
if (isCreated && this.connect) {
await this.connect(options)
return
}
} else {
this.payload.logger.error({
err,
msg: `Error: cannot connect to Postgres. Details: ${err.message}`,
})
}
if (typeof this.rejectInitializing === 'function') {
this.rejectInitializing()
}
throw new Error(`Error: cannot connect to Postgres: ${err.message}`)
}
await this.createExtensions()
await assertOperatorHandlerExtensionsInstalled({
drizzle: this.drizzle,
operatorHandlers: this.operatorHandlers,
})
// Only push schema if not in production
if (
process.env.NODE_ENV !== 'production' &&
process.env.PAYLOAD_MIGRATING !== 'true' &&
this.push !== false
) {
await pushDevSchema(this as unknown as DrizzleAdapter)
}
View on GitHub (pinned to 00c58b35c0)
Solutions
- Verify the connection string and credentials with `psql` from the same host.
- Confirm Postgres is running and reachable: `nc -zv <host> 5432`.
- Ensure env vars are actually loaded into the process.
- Match SSL settings (`ssl: true`/`sslmode`) to what the server requires.
- Confirm the target database exists and the user has CONNECT privileges.
Example fix
// before
payload.init({ secret, db: postgresAdapter({ pool: { connectionString: process.env.DATABASE_URL } }) }) // DATABASE_URL unset
// after
payload.init({ secret, db: postgresAdapter({ pool: { connectionString: process.env.DATABASE_URL } }) })
// .env: DATABASE_URL=postgres://user:pass@host:5432/db Defensive patterns
Strategy: retry
Validate before calling
async function assertPostgresReachable(connectionString, timeoutMs = 5000) {
const u = new URL(connectionString)
const ok = await probeTcp(u.hostname, Number(u.port || 5432), timeoutMs)
if (!ok) throw new Error(`Postgres unreachable at ${u.host}`)
} Type guard
const looksLikeValidPostgresUrl = (s) => {
try { const u = new URL(s); return u.protocol === 'postgres:' || u.protocol === 'postgresql:' }
catch { return false }
} Try / catch
try { await payload.init() }
catch (e) { if (/cannot connect to Postgres/.test(e.message)) { await backoffRetry(() => payload.init()) } else throw e } Prevention
- Validate the connection string is present and well-formed at boot.
- Keep Postgres credentials in env vars managed by a secret store.
- Verify network/SG rules allow egress to port 5432 from the app host.
- Add a startup readiness check that opens a real connection before serving traffic.
When it happens
Trigger: `payload.init()` cannot reach Postgres: invalid connection string/pool config, wrong host/port, bad credentials, the database does not exist, SSL/TLS misconfiguration, or a network/firewall block.
Common situations: Wrong/missing `pool`/`poolURL`/`DATABASE_URL` env var; rotated credentials; Postgres service not running; security group/firewall blocks port 5432; SSL required by server but not configured; DNS resolution failure.
Related errors
- Error: cannot connect to Postgres: ${err.message}
- Error: cannot connect to SQLite: ${message}
- Operator handler "${handler.name}" requires the "${extension
- Error: missing MongoDB connection URL.
- Error: cannot connect to MongoDB: ${msg}
AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12).
Data as JSON: /api/errors/575c63d06d20a5da.
Report an issue: GitHub.