mongodb/node-mongodb-native · critical · MongoRuntimeError
Server returned an invalid signature
Error message
Server returned an invalid signature
What it means
Thrown by continueScramConversation() (scram.ts:189) as a MongoRuntimeError after the final saslContinue when the server's signature (parsedResponse.v) does not match the HMAC the client computed from its own server key. A signature mismatch means the password is wrong OR the server is not who it claims to be (the SCRAM server proof verifies both).
Source
Thrown at src/cmap/auth/scram.ts:189
const payloadString = ByteUtils.toUTF8(payload.buffer, 0, payload.position, false);
const authMessage = [firstMessage, payloadString, withoutProof].join(',');
const clientSignature = await HMAC(cryptoMethod, storedKey, authMessage);
const clientProof = `p=${xor(clientKey, clientSignature)}`;
const clientFinal = [withoutProof, clientProof].join(',');
const serverSignature = await HMAC(cryptoMethod, serverKey, authMessage);
const saslContinueCmd = {
saslContinue: 1,
conversationId: response.conversationId,
payload: new Binary(ByteUtils.fromUTF8(clientFinal))
};
const r = await connection.command(ns(`${db}.$cmd`), saslContinueCmd, undefined);
const parsedResponse = parsePayload(r.payload);
if (!compareDigest(ByteUtils.fromBase64(parsedResponse.v), serverSignature)) {
throw new MongoRuntimeError('Server returned an invalid signature');
}
if (r.done !== false) {
// If the server sends r.done === true we can save one RTT
return;
}
const retrySaslContinueCmd = {
saslContinue: 1,
conversationId: r.conversationId,
payload: ByteUtils.allocate(0)
};
await connection.command(ns(`${db}.$cmd`), retrySaslContinueCmd, undefined);
}
function parsePayload(payload: Binary) {
const payloadStr = ByteUtils.toUTF8(payload.buffer, 0, payload.position, false);View on GitHub (pinned to 3366c21a63)
Solutions
- Double-check the password - test it with 'mongosh' using the same URI
- Verify the username is correct and exists in the configured authSource
- Confirm authSource matches where the user was created (admin vs application db)
- Reset the user's password server-side and update the client URI
Example fix
// before
const client = new MongoClient('mongodb://user:oldpass@host/?authSource=admin');
// after
const client = new MongoClient('mongodb://user:newpass@host/?authSource=admin'); Defensive patterns
Strategy: try-catch
Try / catch
try {
await client.connect();
await client.db().command({ ping: 1 });
} catch (e) {
if (e instanceof MongoRuntimeError && /invalid signature/i.test(e.message)) {
// wrong password or wrong user - verify credentials with mongosh
}
throw e;
} Prevention
- Verify credentials with mongosh using the identical URI before coding
- Confirm authSource matches the database where the user was created
- After server-side password rotations, update the client immediately
- Encode special characters in the password via encodeURIComponent
When it happens
Trigger: Incorrect password supplied for the username; corrupted credentials during transit; a malicious server impersonating the real one without the correct shared secret; mismatched authSource causing auth against a different user store.
Common situations: Wrong password in the connection string; credentials rotated server-side but not in the client; typo in username leading to a different (existing) user whose password differs; copying a connection string between environments without updating the password.
Related errors
- Password cannot be empty
- Username required for mechanism '${this.mechanism}'
- AuthContext must provide credentials.
- Server returned an invalid iteration count ${iterations}
- Server returned an invalid nonce: ${rnonce}
AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04).
Data as JSON: /data/errors/1cfea67daf0769d6.json.
Report an issue: GitHub.