sidorares/node-mysql2 · error · TypeError

HandshakeResponse authPluginName must be a string when provi

Error message

HandshakeResponse authPluginName must be a string when provided

What it means

When a caller supplies both `authToken` and `authPluginName` to HandshakeResponse (the optimised pre-calculated-token path), `authPluginName` must be a string. If it is present but non-string, HandshakeResponse throws at construction. Standard connection setup never sets these fields, so this is only relevant to advanced/internal callers.

Source

Thrown at lib/packets/handshake_response.js:34

    this.authPluginData2 = handshake.authPluginData2;
    this.compress = handshake.compress;
    this.clientFlags = handshake.flags;
    this.mariadbExtendedClientFlags = handshake.mariadbExtendedClientFlags || 0;

    // Accept pre-calculated authToken and authPluginName from caller
    // This allows the caller to optimize by using the server's preferred auth method
    if (
      handshake.authToken !== undefined &&
      handshake.authPluginName !== undefined
    ) {
      // Validate types to fail fast with clear errors
      if (!Buffer.isBuffer(handshake.authToken)) {
        throw new TypeError(
          'HandshakeResponse authToken must be a Buffer when provided'
        );
      }
      if (typeof handshake.authPluginName !== 'string') {
        throw new TypeError(
          'HandshakeResponse authPluginName must be a string when provided'
        );
      }
      this.authToken = handshake.authToken;
      this.authPluginName = handshake.authPluginName;
    } else {
      // Fallback to legacy behavior: calculate mysql_native_password token
      // TODO: pre-4.1 auth support
      let authToken;
      if (this.passwordSha1) {
        authToken = auth41.calculateTokenFromPasswordSha(
          this.passwordSha1,
          this.authPluginData1,
          this.authPluginData2
        );
      } else {
        authToken = auth41.calculateToken(
          this.password,

View on GitHub (pinned to 5ebe8903d6)

Solutions

  1. Ensure authPluginName is a string: `new HandshakeResponse({ ..., authToken, authPluginName: String(name) })`.
  2. Omit both fields if you do not need the optimised path.

Example fix

// before
new HandshakeResponse({ ..., authToken, authPluginName: 42 });

// after
new HandshakeResponse({ ..., authToken, authPluginName: 'caching_sha2_password' });
Defensive patterns

Strategy: type-guard

Validate before calling

function buildHandshakeOpts(opts) {
  if (opts.authPluginName !== undefined && typeof opts.authPluginName !== 'string') {
    throw new TypeError('authPluginName must be a string');
  }
  return opts;
}

Type guard

function isValidAuthPluginName(name) {
  return name == null || typeof name === 'string';
}

Prevention

When it happens

Trigger: Constructing HandshakeResponse with `authPluginName` set to a non-string (number, object, Buffer) alongside an `authToken`. Happens in custom handshake code or tests that build the packet manually.

Common situations: A fork or test harness passing the plugin name from an unvalidated source; confusing authPluginName (string) with authToken (Buffer).

Related errors


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