sidorares/node-mysql2 · error · Error

Callback function is not available with promise clients.

Error message

Callback function is not available with promise clients.

What it means

PromiseConnection.query() inspects its second argument and throws synchronously if it is a function. The promise API intentionally removes the callback signature of the callback API: a query returns a Promise and cannot accept a node-style callback. Passing (sql, cb) or (sql, params, cb) hits the typeof === 'function' check at connection.js:34 and throws before a Promise is constructed.

Source

Thrown at lib/promise/connection.js:35

    this.Promise = promiseImpl || Promise;
    inheritEvents(connection, this, [
      'error',
      'drain',
      'connect',
      'end',
      'enqueue',
    ]);
  }

  release() {
    this.connection.release();
  }

  query(query, params) {
    const c = this.connection;
    const stackHolder = captureStackHolder(PromiseConnection.prototype.query);
    if (typeof params === 'function') {
      throw new Error(
        'Callback function is not available with promise clients.'
      );
    }
    return new this.Promise((resolve, reject) => {
      const done = makeDoneCb(resolve, reject, stackHolder);
      if (params !== undefined) {
        c.query(query, params, done);
      } else {
        c.query(query, done);
      }
    });
  }

  execute(query, params) {
    const c = this.connection;
    const stackHolder = captureStackHolder(PromiseConnection.prototype.execute);
    if (typeof params === 'function') {
      throw new Error(

View on GitHub (pinned to 5ebe8903d6)

Solutions

  1. Drop the callback and await the returned promise: const [rows] = await conn.query('SELECT 1')
  2. Pass params as an array, not a function: await conn.query('SELECT ? FROM t', [col])
  3. If you need callback semantics, use the non-promise connection (omit .promise())
  4. Use try/catch around await to handle errors instead of an error-first callback

Example fix

// before
conn.promise().query('SELECT 1', (err, rows) => { /* never runs */ });

// after
const [rows] = await conn.promise().query('SELECT 1');
Defensive patterns

Strategy: type-guard

Validate before calling

function promiseQuery(conn, sql, params) {
  if (typeof params === 'function') {
    throw new TypeError('mysql2 promise API: do not pass a callback to query(); await the result');
  }
  return params !== undefined ? conn.query(sql, params) : conn.query(sql);
}

Type guard

function isCallbackArg(arg) {
  return typeof arg === 'function';
}

Try / catch

try {
  const [rows] = await conn.promise().query('SELECT 1');
} catch (err) {
  // note: this specific error throws synchronously, so the try must wrap the call itself
  console.error(err);
}

Prevention

When it happens

Trigger: Calling const res = conn.promise().query('SELECT 1', (err, rows) => {}), or migrating callback-style code to the promise API without removing the callback argument, or passing a function as the params argument by mistake.

Common situations: Refactoring from callback API to promise API and forgetting to drop the callback, mixing code styles in a migration, or accidentally passing a comparator/iterator function where params were expected.

Related errors


AI-assisted analysis of sidorares/node-mysql2@5ebe8903d6 (2026-08-03). Data as JSON: /data/errors/2adfbaff897e232e.json. Report an issue: GitHub.