payloadcms/payload · critical · APIError
beginTransaction called while no connection to the database
Error message
beginTransaction called while no connection to the database exists
What it means
Thrown by the MongoDB adapter's `beginTransaction` when `this.connection` is falsy — Mongoose has no live connection. Transactions require a session bound to an active connection, so the adapter aborts immediately instead of producing a useless session.
Source
Thrown at packages/db-mongodb/src/transactions/beginTransaction.ts:17
import type { TransactionOptions } from 'mongodb'
import type { BeginTransaction } from 'payload'
import { APIError } from 'payload'
import { v4 as uuid } from 'uuid'
import type { MongooseAdapter } from '../index.js'
// Needs await to fulfill the interface
// @ts-expect-error TransactionOptions isn't compatible with BeginTransaction of the DatabaseAdapter interface.
// eslint-disable-next-line @typescript-eslint/require-await
export const beginTransaction: BeginTransaction = async function beginTransaction(
this: MongooseAdapter,
options: TransactionOptions,
) {
if (!this.connection) {
throw new APIError('beginTransaction called while no connection to the database exists')
}
const client = this.connection.getClient()
const id = uuid()
if (!this.sessions[id]) {
this.sessions[id] = client.startSession()
}
if (this.sessions[id]?.inTransaction()) {
this.payload.logger.warn('beginTransaction called while transaction already exists')
} else {
this.sessions[id]?.startTransaction(options || (this.transactionOptions as TransactionOptions))
}
return id
}
View on GitHub (pinned to 00c58b35c0)
Solutions
- Await `payload.init()` (and the underlying connect) before serving any request.
- Verify the MongoDB URI/host is reachable and credentials are valid.
- Guard with `adapter.connection && adapter.connection.readyState === 1` before starting a transaction.
- In serverless, reuse the connection across invocations and do not close it between calls.
Example fix
// before
app.post('/x', handler) // starts before DB is up
// after
await payload.init()
app.post('/x', handler) Defensive patterns
Strategy: validation
Validate before calling
function assertConnected(adapter) {
if (!adapter.connection || adapter.connection.readyState !== 1)
throw new Error('MongoDB connection not ready')
} Type guard
const isMongoConnected = (adapter) => Boolean(adapter.connection) && adapter.connection.readyState === 1
Try / catch
try { await payload.db.beginTransaction() }
catch (e) { if (/no connection to the database/.test(e.message)) await waitForDb(payload) else throw e } Prevention
- Await payload.init() before serving requests.
- In serverless, reuse the connection; do not disconnect between invocations.
- Add a readiness check that verifies connection.readyState === 1.
When it happens
Trigger: Any transactional operation (payload.db.beginTransaction, or any op wrapped in a transaction) that runs before `payload.init()`/`connect` resolves, after the connection was closed/dropped, or when the initial connect failed but the app kept serving requests.
Common situations: Handling requests during startup before the init promise resolves; MongoDB unreachable at boot but the process continues; calling `mongoose.disconnect()`/`db.close()` then querying; serverless cold-start races where the connection isn't established before the first transactional request.
Related errors
- Error: cannot connect to Postgres: ${err.message}
- Error: cannot connect to Postgres: ${err.message}
- Error: cannot connect to SQLite: ${message}
- Error: cannot connect to SQLite: ${message}
- Error: missing MongoDB connection URL.
AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12).
Data as JSON: /api/errors/9a2ca1237cf612dc.
Report an issue: GitHub.