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() (the wrapper returned by connection.promise() and by mysql2/promise) detects a function passed as the second argument — the legacy callback position of the callback API — and throws synchronously. The promise API intentionally rejects the callback pattern: use await (and the returned promise) or use the callback API, never both on the same client. Because this is a synchronous throw (not a rejected promise), it propagates immediately unless the call is inside try/catch or an async function.

Solutions

  1. Drop the callback and await the result: const [rows] = await conn.query(sql).
  2. If you must use callbacks, import from 'mysql2' (callback API) instead of 'mysql2/promise', or use the unwrapped connection.
  3. Wrap the call in try/catch (or an async function with await) so the synchronous throw becomes a catchable rejection.

Example fix

// before
const conn = await createConnection({ host: 'localhost' });
conn.query('SELECT 1', (err, rows) => { if (err) throw err; console.log(rows); });
// after
const conn = await createConnection({ host: 'localhost' });
const [rows] = await conn.query('SELECT 1');
console.log(rows);
Defensive patterns

Strategy: type-guard

Validate before calling

function isThenable(v) {
  return v != null && typeof v.then === 'function';
}

// ensure you never pass a function as the 2nd arg to a promise query
if (typeof params === 'function') {
  throw new TypeError('Pass a callback to the callback API, not the promise API');
}

Type guard

function isPromiseConnection(c) {
  // promise clients expose a `.Promise` property and lack the callback-style internals
  return c != null && 'Promise' in c && typeof c.query === 'function' && c.query.length < 3;
}

Try / catch

try {
  const [rows] = await conn.query(sql, params);
} catch (err) {
  if (/Callback function is not available/.test(err.message)) {
    // caller mixed APIs: re-issue without the callback
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Calling conn.query(sql, cb) on a connection obtained via .promise() or imported from 'mysql2/promise'. Example: const conn = (await createConnection({})).promise(); conn.query('SELECT 1', (err, rows) => {...}).

Common situations: Migrating from the callback API to the promise API and leaving a callback in place; copy-pasting a callback-style snippet into a file that imports from 'mysql2/promise'; refactoring a helper that still passes a callback through.

Related errors


AI-assisted analysis of sidorares/node-mysql2@8b1f829d37 (2026-08-11). Data as JSON: /api/errors/2adfbaff897e232e. Report an issue: GitHub.

Appendix: 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 8b1f829d37)