Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

db-postgres: connect() rejects its `initializing` promise with no argument, producing an unhandledRejection with reason `undefined`

Abierto Apto para principiantes
#18,656 1 comentario 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

@Metehan-Bicer ya está trabajando en esto.

Desde el 10/10/2026.

  • #18658 de @Metehan-Bicer — abierto

Evaluación

Dificultad
2/5
Tiempo estimado
1-3 horas
Aptitud para principiantes
76/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
node.js, postgresql, typescript
Área
backend, database

Línea de trabajo

Lee packages/db-postgres/src/index.ts y packages/db-postgres/src/connect.ts; después, revisa el tipo de rejectInitializing en packages/drizzle/src/types.ts y el consumidor en packages/drizzle/src/transactions/beginTransaction.ts. El issue describe dos posibles soluciones. Sigue cómo los errores de conexión llegan a la promesa y cómo beginTransaction gestiona el rechazo. La tarea estará terminada cuando el rechazo huérfano ya no informe de undefined y los errores de conexión sigan propagándose.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

area: db-postgres Bug
Describe the Bug

@payloadcms/db-postgres rejects its internal initializing promise with no argument when connect() fails. Because the only thing that ever awaits that promise is beginTransaction, a failed connect on a request path that opens no transaction leaves the rejection unhandled — and since the reason is undefined, Node attaches no stack to it.

The result is an unhandledRejection with reason === undefined. In an app with Sentry (or any unhandledRejection reporter) wired up, that arrives as an event with no message, no stack and no in-app frames, pointing only at the reporter's own handler. It is effectively undebuggable from the report: nothing in it names Payload, Postgres, or the connection at all.

The two lines, at v3.90.2:

  • packages/db-postgres/src/index.ts#L80-L82 — the promise is created and no handler is attached:

    const initializing = new Promise<void>((res, rej) => {
      resolveInitializing = res
      rejectInitializing = rej
    })
    
  • packages/db-postgres/src/connect.ts#L109-L111 — it is rejected with nothing, and then a separate real Error is thrown:

    if (typeof this.rejectInitializing === 'function') {
      this.rejectInitializing()          // ← no argument ⇒ rejects with `undefined`
    }
    throw new Error(`Error: cannot connect to Postgres: ${err.message}`)
    

Still present on main (packages/db-postgres/src/connect.ts, this.rejectInitializing() immediately before the throw). The type itself guarantees it can never carry a reason — rejectInitializing: () => void, declared with no parameter, in packages/drizzle/src/types.ts and the db-postgres types.

The only consumer is packages/drizzle/src/transactions/beginTransaction.ts (await this.initializing). packages/drizzle/src/destroy.ts replaces the promise rather than awaiting it. So on any read path that does not begin a transaction, nothing is attached when the rejection lands.

Two suggested fixes, either of which is sufficient:

  1. Pass the error: this.rejectInitializing(err), and widen the type to (err?: unknown) => void. The rejection then at least carries a stack for whoever is listening.
  2. Attach a no-op handler where the promise is created, so the orphan can never surface: initializing.catch(() => {}). connect() already throws the real error separately, and beginTransaction's own await still rejects, so nothing is swallowed.

(1) is the more useful of the two; doing both costs nothing.

Link to the code that reproduces this issue

https://github.com/payloadcms/payload/blob/v3.90.2/packages/db-postgres/src/connect.ts#L109-L111

I have not pushed a create-payload-app scaffold for this one, because the defect is visible in the published source above and does not depend on app config: rejectInitializing is typed () => void, it is called with no argument, and the promise it rejects has no handler attached at creation. Happy to put a scaffold together if you'd rather have one to run — say so and I will.

Reproduction Steps

Any postgresAdapter app where connect() fails will do it. Forcing it deterministically:

  1. Build the app and start it (output: standalone in my case, but plain next start behaves the same).

  2. Set connectionTimeoutMillis on the adapter's pool low enough that the pool's timer expires during the first server render, which blocks the event loop while the CMS config is built. With connectionTimeoutMillis: 1 through 10 it fires every time:

    db: postgresAdapter({
      pool: { connectionString: process.env.DATABASE_URL, connectionTimeoutMillis: 1 },
    })
    
  3. Request any page that reads from the database but opens no transaction (a plain payload.find() in a server component is enough).

  4. Observe two things in the output: Payload's own Error: cannot connect to Postgres: Connection terminated due to connection timeout — correct and useful — and, separately, an unhandledRejection whose reason is undefined.

With a listener installed to inspect it:

process.on('unhandledRejection', (reason) => {
  console.log('typeof reason:', typeof reason, '| isError:', reason instanceof Error)
})
// → typeof reason: undefined | isError: false

Patching the reject capability of new Promise(executor) to log a stack when called with a non-Error names the call site directly:

!! new Promise(…) reject() with a non-Error reason: undefined
   at Object.rejectInitializing (…)
   at Object.i [as connect]  (…/connect.js)
   at async …init            (…)

Ruled out below Payload, by reading the installed source, so that the report lands in the right place:

  • [email protected] can only reject its connect promise with a truthy value — err ? rej(err) : res(client).
  • [email protected]'s Client.end() with no callback returns a promise with no reject path at all.
  • @opentelemetry/[email protected]'s handleConnectResult re-rejects the identical error.
Which area(s) are affected?

area: db-postgres

Environment Info
payload:              3.90.2
@payloadcms/db-postgres: 3.90.2
@payloadcms/drizzle:  3.90.2
pg:                   8.20.0
pg-pool:              3.13.0
next:                 15.4.11
node:                 22.16.0 (also reproduced on 22.23.1)
Lenguaje dominante
TypeScript
Estrellas
45.3k
Forks
4.3k
Merge medio
1 d 21 h
PR fusionados (30 d)
272

Preparar el entorno

Abrir en Codespaces

Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de payloadcms/payload

Todos los issues de payloadcms/payload

Issues similares

Más issues de TypeScript

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.