RocketChat/Rocket.Chat · critical · Error
Failed to encode private key with provided password.
Error message
Failed to encode private key with provided password.
What it means
persistKeys throws this when keychain.encryptKey(private_key, password) returns a falsy value, meaning the password-based encryption of the private key failed before anything is sent to /v1/e2e.setUserPublicAndPrivateKeys. The guard exists because a falsy encoded key would otherwise persist unusable key material server-side.
Source
Thrown at apps/meteor/client/lib/e2ee/rocketchat.e2e.ts:291
}
removeInstanceByRoomId(rid: IRoom['_id']): void {
delete this.instancesByRoomId[rid];
}
private async persistKeys(
{ public_key, private_key }: KeyPair,
password: string,
{ force }: { force: boolean } = { force: false },
): Promise<void> {
if (typeof public_key !== 'string' || typeof private_key !== 'string') {
throw new Error('Failed to persist keys as they are not strings.');
}
const encodedPrivateKey = await this.keychain.encryptKey(private_key, password);
if (!encodedPrivateKey) {
throw new Error('Failed to encode private key with provided password.');
}
await sdk.rest.post('/v1/e2e.setUserPublicAndPrivateKeys', {
public_key,
private_key: JSON.stringify(encodedPrivateKey),
force,
});
}
async acceptSuggestedKey(rid: string): Promise<void> {
await sdk.rest.post('/v1/e2e.acceptSuggestedGroupKey', {
rid,
});
}
async rejectSuggestedKey(rid: string): Promise<void> {
await sdk.rest.post('/v1/e2e.rejectSuggestedGroupKey', {
rid,View on GitHub (pinned to b2c16d5842)
Solutions
- Verify the password argument is non-empty and is the password the keychain expects (account password in the default flow).
- Retry the operation once — transient crypto/derivation failures can yield a falsy result.
- If it persists, reset E2EE state, regenerate the key pair, and persist with { force: true }.
Example fix
// before
await e2e.persistKeys(keyPair, password);
// after
for (let attempt = 0; attempt < 2; attempt++) {
try {
await e2e.persistKeys(keyPair, password, { force: attempt > 0 });
break;
} catch (e) {
if (attempt === 1) throw e;
password = await promptPasswordAgain();
}
} Defensive patterns
Strategy: retry
Validate before calling
if (!password) {
throw new Error('E2EE password required');
}
await e2e.persistKeys(keyPair, password); Try / catch
let lastErr: unknown;
for (let attempt = 0; attempt < 2; attempt++) {
try {
await e2e.persistKeys(keyPair, password, { force: attempt > 0 });
lastErr = undefined;
break;
} catch (e) {
lastErr = e;
password = await promptPasswordAgain(); // fresh, verified password
}
}
if (lastErr) throw lastErr; Prevention
- Validate the password is non-empty and matches the account flow before persisting keys.
- Never ignore a falsy encryptKey result — abort and re-derive instead of persisting.
- If retries keep failing, reset E2EE state and regenerate keys with force: true.
When it happens
Trigger: Calling persistKeys with an empty or malformed password, when password-based key derivation inside the keychain fails (transient WebCrypto issue, non-secure context), or when a custom keychain implementation returns undefined on error instead of throwing.
Common situations: E2EE setup where the supplied password does not match expectations (account password flow), corrupted keychain state after a browser storage issue, private/incognito modes restricting crypto or storage APIs.
Related errors
- Failed to persist keys as they are not strings.
- error-e2e-enabled
- error-invalid-keys
- error-invalid-user
- error-invalid-room
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/168900d4aac20eb8.
Report an issue: GitHub.