sidorares/node-mysql2 · error · TypeError

Bind parameters must not contain undefined. To pass SQL…

Error message

Bind parameters must not contain undefined. To pass SQL NULL specify JS null

What it means

In Connection.execute (lib/base/connection.js:789-800), each bind parameter is checked and a value strictly equal to undefined throws, because mysql2 cannot encode undefined as a SQL value. The driver deliberately distinguishes undefined (a programming mistake) from null (which maps to SQL NULL). This is a fail-fast guard before the prepared-statement encode path.

Solutions

  1. Coalesce to null explicitly: [value ?? null] to express SQL NULL for missing values.
  2. Track down the source of the undefined and fix the data path so the value is intentional.
  3. Add a pre-flight filter: values.map(v => v === undefined ? null : v) if a deliberate default-to-NULL policy is acceptable.

Example fix

// before
connection.execute('INSERT INTO t (a, b) VALUES (?, ?)', [req.body.a, req.body.b]);

// after
connection.execute('INSERT INTO t (a, b) VALUES (?, ?)', [req.body.a ?? null, req.body.b ?? null]);
Defensive patterns

Strategy: validation

Validate before calling

const safeParams = (vals) => vals.map(v => v === undefined ? null : v);
// conn.execute(sql, safeParams(values));

Type guard

const hasNoUndefined = (vals) => vals.every(v => v !== undefined);

Prevention

When it happens

Trigger: connection.execute(sql, [someVar]) where someVar was never assigned; destructuring an object that omits a key; a JSON.parse result missing an expected field; passing [undefined] explicitly.

Common situations: Optional request fields that are absent (req.body.middleName is undefined); a typo in a property name used to fill the params array; migration from a driver that silently coerced undefined to null.

Related errors


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

Appendix: source

Thrown at lib/base/connection.js:797

    }
    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'
          );
        }
      });
    }
    const executeCommand = new Commands.Execute(options, cb);

    const prepareAndExecute = (errorCb) => {
      const prepareCommand = new Commands.Prepare(options, (err, stmt) => {
        if (err) {
          // skip execute command if prepare failed
          executeCommand.start = function () {
            return null;

View on GitHub (pinned to 8b1f829d37)