payloadcms/payload · error · APIError
Operator handler "${handler.name}" requires the "${extension
Error message
Operator handler "${handler.name}" requires the "${extensionName}" Postgres extension, which is not installed on this database. Add it to the adapter's "extensions" option, or install it manually with CREATE EXTENSION. What it means
A connection-time `APIError` from `assertOperatorHandlerExtensionsInstalled`: a registered Postgres operator handler declares a `requiredExtensions` entry (e.g. the built-in `postgres-unaccent` handler needs `unaccent`) but that extension is not present in `pg_extension`. The check runs after `createExtensions`, so declaring the extension in the adapter `extensions` option would have installed it automatically; the throw means neither declaration nor manual install happened.
Source
Thrown at packages/drizzle/src/postgres/query/assertOperatorHandlerExtensionsInstalled.ts:37
drizzle,
operatorHandlers,
}: Args): Promise<void> => {
const requiredExtensionsByHandler = operatorHandlers.flatMap((handler) =>
(handler.requiredExtensions ?? []).map((extensionName) => ({ extensionName, handler })),
)
if (!requiredExtensionsByHandler.length) {
return
}
const { rows: installedExtensionRows } = await drizzle.execute<{ extname: string }>(
sql`SELECT extname FROM pg_extension`,
)
const installedExtensions = new Set(installedExtensionRows.map((row) => row.extname))
for (const { extensionName, handler } of requiredExtensionsByHandler) {
if (!installedExtensions.has(extensionName)) {
throw new APIError(
`Operator handler "${handler.name}" requires the "${extensionName}" Postgres extension, which is not installed on this database. Add it to the adapter's "extensions" option, or install it manually with CREATE EXTENSION.`,
)
}
}
}
View on GitHub (pinned to 00c58b35c0)
Solutions
- Add the extension to the adapter's `extensions` option so Payload installs it on connect, e.g. `extensions: { unaccent: true }`.
- Alternatively install the extension manually: `CREATE EXTENSION IF NOT EXISTS unaccent;`.
- Ensure the DB role has CREATE privilege for extensions (or pre-install as superuser).
- If you don't actually need the handler, remove it from `operatorHandlers`.
Example fix
// before
new PostgresAdapter({
pool,
postgresQuery: { operatorHandlers: [postgresUnaccent()] },
})
// after
new PostgresAdapter({
pool,
extensions: { unaccent: true },
postgresQuery: { operatorHandlers: [postgresUnaccent()] },
}) Defensive patterns
Strategy: validation
Validate before calling
// Before connecting, ensure every handler extension is declared
const required = (operatorHandlers ?? [])
.flatMap(h => h.requiredExtensions ?? [])
const declared = Object.keys(adapterOptions.extensions ?? {})
const missing = required.filter(e => !declared.includes(e))
if (missing.length) {
throw new Error(`Declare these extensions on the adapter: ${missing.join(', ')}`)
}
new PostgresAdapter(adapterOptions) Type guard
const handlerRequiresExtension = (h): h is { requiredExtensions: string[] } =>
Array.isArray(h?.requiredExtensions) && h.requiredExtensions.length > 0 Try / catch
try {
await payload.db.init()
} catch (err) {
if (/requires the ".*" Postgres extension/.test(String(err?.message))) {
payload.logger.error('Add the missing extension to the adapter extensions option or run CREATE EXTENSION.')
}
throw err
} Prevention
- Whenever you register an operator handler with requiredExtensions, also add those extensions to the adapter extensions option.
- Grant the DB role privileges to CREATE EXTENSION, or pre-install extensions via infrastructure.
- In CI, run migrations against a DB that mirrors production's extensions.
When it happens
Trigger: Configuring `postgresQuery.operatorHandlers` (e.g. `postgresUnaccent()`) without listing the matching extension in the adapter `extensions` option, against a database where that extension isn't pre-installed. Also when an operator handler from a plugin/custom code declares `requiredExtensions` the DB doesn't satisfy.
Common situations: Using accent-insensitive search (`postgresUnaccent`) on a managed Postgres without the `unaccent` extension; deploying to a fresh DB; a custom operator handler requiring `pg_trgm`/`fuzzystrmatch` without declaring it.
Related errors
- Error: cannot connect to Postgres: ${err.message}
- Error: cannot connect to Postgres: ${err.message}
- Error: missing MongoDB connection URL.
- Error: cannot connect to SQLite: ${message}
- Invalid template given
AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12).
Data as JSON: /api/errors/47a4258f88fc423c.
Report an issue: GitHub.