brianc/node-postgres · error · Error

Both useLibpqCompat and uselibpqcompat are set. Please use o

Error message

Both useLibpqCompat and uselibpqcompat are set. Please use only one of them.

What it means

Thrown by pg-connection-string's parse() when the caller passes the option { useLibpqCompat: true } AND the connection string itself also contains the query parameter uselibpqcompat=true. The library exposes two ways to opt into libpq-compatible SSL semantics, and having both active simultaneously is treated as a configuration conflict. The guard at index.js:102 explicitly checks options.useLibpqCompat && config.uselibpqcompat and throws so the intent is unambiguous.

Source

Thrown at packages/pg-connection-string/index.js:103

  }

  // Only try to load fs if we expect to read from the disk
  const fs = config.sslcert || config.sslkey || config.sslrootcert ? require('fs') : null

  if (config.sslcert) {
    config.ssl.cert = fs.readFileSync(config.sslcert).toString()
  }

  if (config.sslkey) {
    config.ssl.key = fs.readFileSync(config.sslkey).toString()
  }

  if (config.sslrootcert) {
    config.ssl.ca = fs.readFileSync(config.sslrootcert).toString()
  }

  if (options.useLibpqCompat && config.uselibpqcompat) {
    throw new Error('Both useLibpqCompat and uselibpqcompat are set. Please use only one of them.')
  }

  if (config.uselibpqcompat === 'true' || options.useLibpqCompat) {
    switch (config.sslmode) {
      case 'disable': {
        config.ssl = false
        break
      }
      case 'prefer': {
        config.ssl.rejectUnauthorized = false
        break
      }
      case 'require': {
        if (config.sslrootcert) {
          // If a root CA is specified, behavior of `sslmode=require` will be the same as that of `verify-ca`
          config.ssl.checkServerIdentity = function () {}
        } else {
          config.ssl.rejectUnauthorized = false

View on GitHub (pinned to c5e8c9a57b)

Solutions

  1. Remove uselibpqcompat from the connection string / DATABASE_URL query parameters, keeping only the programmatic { useLibpqCompat: true } option.
  2. Alternatively, remove { useLibpqCompat: true } from your options/config object and rely solely on the connection-string parameter.
  3. Centralize SSL configuration in one place (either the connection string or the options object) and document the chosen approach so contributors do not re-add the other form.

Example fix

// before
const pool = new Pool({
  connectionString: 'postgres://host/db?sslmode=require&uselibpqcompat=true',
  useLibpqCompat: true,
});

// after (pick ONE)
const pool = new Pool({
  connectionString: 'postgres://host/db?sslmode=require&uselibpqcompat=true',
});
// or
const pool = new Pool({
  connectionString: 'postgres://host/db?sslmode=require',
  useLibpqCompat: true,
});
Defensive patterns

Strategy: validation

Validate before calling

const { parse } = require('pg-connection-string');

function safeParse(connStr, options = {}) {
  // Check the connection string for uselibpqcompat before parsing
  const hasParam = /[?&]uselibpqcompat=/.test(connStr);
  if (options.useLibpqCompat && hasParam) {
    throw new Error(
      'Conflict: remove uselibpqcompat from the connection string OR remove useLibpqCompat from options.'
    );
  }
  return parse(connStr, options);
}

Try / catch

try {
  const config = parseIntoClientConfig(connStr, { useLibpqCompat: true });
} catch (err) {
  if (/useLibpqCompat and uselibpqcompat/i.test(err.message)) {
    // Strip the duplicate from the connection string and retry without the option
    const cleaned = connStr.replace(/([?&])uselibpqcompat=[^&]*/i, '$1');
    config = parseIntoClientConfig(cleaned);
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Calling parse(connStr, { useLibpqCompat: true }) or new Pool({ connectionString, useLibpqCompat: true }) where connStr already contains '?...&uselibpqcompat=true'. Also triggered via ConnectionParameters when config.useLibpqCompat is set alongside a DATABASE_URL containing uselibpqcompat.

Common situations: A team standardizes SSL behavior by adding useLibpqCompat:true to pool config, but the DATABASE_URL env var (often set by a PaaS like Heroku/Render) already includes uselibpqcompat=true. Another case: copy-pasting a working psql/libpq connection string that had uselibpqcompat into code that also sets the programmatic option.

Related errors


AI-assisted analysis of brianc/node-postgres@c5e8c9a57b (2026-08-03). Data as JSON: /data/errors/342c261bb0d91d1a.json. Report an issue: GitHub.