sidorares/node-mysql2 · error · TypeError

HandshakeResponse authToken must be a Buffer when provided

Error message

HandshakeResponse authToken must be a Buffer when provided

What it means

HandshakeResponse accepts an optional pre-calculated `authToken` plus `authPluginName` (both must be provided together to take the optimised path). If both keys are present but `authToken` is not a Buffer, it throws at construction. This is an internal/advanced API used to short-circuit the initial handshake token; normal callers never set these fields.

Source

Thrown at lib/packets/handshake_response.js:29

    this.user = handshake.user || '';
    this.database = handshake.database || '';
    this.password = handshake.password || '';
    this.passwordSha1 = handshake.passwordSha1;
    this.authPluginData1 = handshake.authPluginData1;
    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,

View on GitHub (pinned to 5ebe8903d6)

Solutions

  1. Pass authToken as a Buffer: `new HandshakeResponse({ ..., authToken: Buffer.from(token), authPluginName })`.
  2. If you do not need the optimised path, omit both authToken and authPluginName and let HandshakeResponse compute the token.

Example fix

// before
new HandshakeResponse({ ..., authToken: 'raw', authPluginName: 'x' });

// after
new HandshakeResponse({ ..., authToken: Buffer.from('raw'), authPluginName: 'x' });
Defensive patterns

Strategy: type-guard

Validate before calling

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

Type guard

function isValidAuthToken(token) {
  return token == null || Buffer.isBuffer(token);
}

Prevention

When it happens

Trigger: Constructing a HandshakeResponse packet directly (or via a custom auth flow) and passing `authToken` as a string or number while also passing `authPluginName`. Application code using the standard connection API will not hit this because the library computes the token itself.

Common situations: Advanced users building a custom handshake or mocking the packet in tests; a fork/patch that passes a string token by mistake.

Related errors


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