sidorares/node-mysql2 · error · TypeError

Bind parameters must be array if namedPlaceholders…

Error message

Bind parameters must be array if namedPlaceholders parameter is not enabled

What it means

In Connection.execute (lib/base/connection.js:782-788), after resolving named placeholders, if options.values is truthy but not an Array, the driver throws because positional ? placeholders require an array. Passing an object of named values is only valid when config.namedPlaceholders is enabled; otherwise the driver cannot map keys to ? slots.

Solutions

  1. Pass an array: connection.execute(sql, [1]).
  2. Or enable named placeholders: createConnection({ ..., namedPlaceholders: true }) and use :name in SQL with a params object.
  3. If building params dynamically, wrap with Array.from(...) or validate Array.isArray before the call.

Example fix

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

// after (positional)
connection.execute('SELECT * FROM t WHERE id = ?', [1]);
// after (named)
connection.execute('SELECT * FROM t WHERE id = :id', { id: 1 }); // needs namedPlaceholders: true
Defensive patterns

Strategy: validation

Validate before calling

function assertBindArray(values) {
  if (values && !Array.isArray(values)) {
    throw new TypeError('Pass an array for positional placeholders, or enable namedPlaceholders for an object.');
  }
}
// assertBindArray(values) before conn.execute(sql, values);

Type guard

const isBindArray = (v) => Array.isArray(v);

Prevention

When it happens

Trigger: Calling connection.execute('SELECT * FROM t WHERE id = ?', { id: 1 }) without namedPlaceholders; passing a Map or object where an array is expected; mixing the named-parameter style from another driver (pg, mysql2 promise) into a positional execute call.

Common situations: Copy-paste from a pg/node-postgres codebase that uses object params; refactoring a query helper that previously built arrays; confusion between ? and :name placeholder styles.

Related errors


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

Appendix: source

Thrown at lib/base/connection.js:785

      } 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 8b1f829d37)