sidorares/node-mysql2 · error · TypeError

Bind parameters must be array if namedPlaceholders parameter

Error message

Bind parameters must be array if namedPlaceholders parameter is not enabled

What it means

In Connection.execute(), after named-placeholder resolution, the bind values are required to be an array. If `options.values` is not an array (e.g. a plain object) and `namedPlaceholders` is not enabled in the connection config, mysql2 throws because it cannot map an object's keys to `?` placeholders. Named-placeholder support must be explicitly opted into via the `namedPlaceholders: true` config.

Source

Thrown at lib/base/connection.js:777

      } else {
        options.values = options.values || values;
      }
    } else if (typeof values === 'function') {
      // execute(sql, cb)
      cb = values;
      options.sql = sql;
      options.values = undefined;
    } else {
      // execute(sql, values, cb)
      options.sql = sql;
      options.values = values;
    }
    this._resolveNamedPlaceholders(options);
    // check for values containing undefined
    if (options.values) {
      //If namedPlaceholder is not enabled and object is passed as bind parameters
      if (!Array.isArray(options.values)) {
        throw new TypeError(
          'Bind parameters must be array if namedPlaceholders parameter is not enabled'
        );
      }
      options.values.forEach((val) => {
        //If namedPlaceholder is not enabled and object is passed as bind parameters
        if (!Array.isArray(options.values)) {
          throw new TypeError(
            'Bind parameters must be array if namedPlaceholders parameter is not enabled'
          );
        }
        if (val === undefined) {
          throw new TypeError(
            'Bind parameters must not contain undefined. To pass SQL NULL specify JS null'
          );
        }
        if (typeof val === 'function') {
          throw new TypeError(
            'Bind parameters must not contain function(s). To pass the body of a function as a string call .toString() first'

View on GitHub (pinned to 5ebe8903d6)

Solutions

  1. Pass bind parameters as an array: `connection.execute(sql, [1, 2])`.
  2. Or enable named placeholders in config: `mysql.createConnection({ ..., namedPlaceholders: true })` and use `:name` placeholders in SQL.

Example fix

// before
connection.execute('SELECT * FROM t WHERE a = ? AND b = ?', { a: 1, b: 2 });

// after — option A: array
connection.execute('SELECT * FROM t WHERE a = ? AND b = ?', [1, 2]);

// after — option B: enable named placeholders
mysql.createConnection({ host, namedPlaceholders: true });
connection.execute('SELECT * FROM t WHERE a = :a AND b = :b', { a: 1, b: 2 });
Defensive patterns

Strategy: validation

Validate before calling

function normalizeParams(values, namedPlaceholders) {
  if (values != null && !Array.isArray(values)) {
    if (!namedPlaceholders) {
      throw new TypeError('Pass an array, or enable namedPlaceholders: true');
    }
  }
  return values;
}
// usage:
const v = normalizeParams(values, conn.config.namedPlaceholders);
conn.execute(sql, v);

Type guard

function isBindableArray(values) {
  return Array.isArray(values);
}

Prevention

When it happens

Trigger: Calling `connection.execute('SELECT * FROM t WHERE a = ? AND b = ?', { a: 1, b: 2 })` (passing an object) without `namedPlaceholders: true`. Or passing an object to `.query()`/`.execute()` values when the config flag is off. Also triggered by accidentally passing a single non-array argument where an array of bind values is expected.

Common situations: Developer assumes object-style parameters work by default (they do in some ORMs); copy-pasting query syntax from a library that uses named params; forgetting to set `namedPlaceholders: true` when migrating from another driver.

Related errors


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