Why can't I catch error thrown from node-postgres?

Viewed 1274

I'm having an issue catching an error thrown from the Node-Postgres NPM package.

The issue seems simple on the surface, but I've tried everything I can think of.

My code is like the following:

import { Pool } from 'pg' // Import postgres connection pool
const pgPool = new Pool()

async function queryDatabase() {
  try {

    // Force TypeError by passing undefined
    let queryResult = await pgPool.query( undefined )

    if ( queryResult.rows.length > 0 ) {
      return queryResult.rows[0]
    }

    return false

  } catch( err ) {

    // Never Reached
    return new Error( 'Test error' )

  }
}
queryDatabase()

And the error is as follows:

TypeError: Client was passed a null or undefined query
at Client.query (~/.../node_modules/pg/lib/client.js:479:11)

The error itself is pretty self-explanatory. I'm forcing the error here, for the sake of trying to handle it in the event that undefined gets passed by mistake. I realize that I can simply perform a check to make sure the input is never null or undefined, but that's not my main concern.

My worry is if I can't catch this error thrown from this package, how many other unforeseen cases am I going to encounter where I simply can't catch and handle a thrown error.

I've tried numerous different approaches - The Async/Await Try/Catch method, shown above - I've tried pgPool.query().then().catch() - Combinations of the two. I've even tried running the catch against the Pool instance itself. No matter what I do, I can't handle the exception without using Node's process.on('unhandledRejection', ...), which is of course a bad idea.

I've been racking my brain on this for hours. Is there any way that I can catch and handle errors like this, so it's not crashing my server every time? Thanks in advance!

1 Answers

I was able to reproduce this and it seems to be an actual bug in the pg-library.

According to the source if you call .query on a pool instance, this instance will attempt to connect and get a client. In this connect-callback the actual query is dispatched to the client-module, which will throw the mentioned type error if the query is nil.

This error is thrown synchronously (i.e. the error is not passed to the callback argument, e.g. callback(new TypeError("...")) and since there's no try/catch around the client.query call in the pool's connect-callback, the error will not be caught by your try/catch.

A potential fix would be to wrap the client.query call in a try catch:

 client.once('error', onError)
      this.log('dispatching query')
      try {
        client.query(text, values, (err, res) => {
          this.log('query dispatched')
          client.removeListener('error', onError)
          if (clientReleased) {
            return
          }
          clientReleased = true
          client.release(err)
          if (err) {
            return cb(err)
          } else {
            return cb(undefined, res)
          }
        })
      }catch(err) {
        return cb(err)
      }

So for now, you probably should create an issue on github and wait for the bugfix or fork the repo and use above workaround, I'm afraid.

Related