Issue:
If you’re using [email protected] with LocalAuth and encounter an issue where the app crashes when a user logs out manually from their phone, this is due to an error in the logout method of the LocalAuth.js file.
The error occurs because the fs.promises.rm() method does not handle retries properly, causing the app to crash if the session directory removal fails.
Solution:
Update the LocalAuth.js file to include a retry mechanism for removing the session directory. Here’s the fix:
Old Code (in LocalAuth.js):
'use strict';
const path = require('path');
const fs = require('fs');
const BaseAuthStrategy = require('./BaseAuthStrategy');
class LocalAuth extends BaseAuthStrategy {
constructor({ clientId, dataPath }={}) {
super();
const idRegex = /^[-_w]+$/i;
if(clientId && !idRegex.test(clientId)) {
throw new Error('Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.');
}
this.dataPath = path.resolve(dataPath || './.wwebjs_auth/');
this.clientId = clientId;
}
async logout() {
if (this.userDataDir) {
await fs.promises.rm(this.userDataDir, { recursive: true, force: true })
.catch((e) => {
throw new Error(e);
});
}
}
}
module.exports = LocalAuth;
New Code (in LocalAuth.js):
'use strict';
const path = require('path');
const fs = require('fs-extra');
const BaseAuthStrategy = require('./BaseAuthStrategy');
// Helper function
async function deleteDirectoryWithRetries(path, retries = 5, delayMs = 500) {
for (let attempt = 1; attempt <= retries; attempt++) {
try {
await fs.rm(path, { recursive: true, force: true });
console.log(`Successfully deleted directory: ${path}`);
return;
} catch (error) {
if (error.code === 'EBUSY' && attempt < retries) {
console.warn(`Attempt ${attempt} to delete directory failed due to EBUSY. Retrying in ${delayMs}ms...`);
await new Promise(res => setTimeout(res, delayMs));
} else {
throw error;
}
}
}
}
////
/**
* Local directory-based authentication
* @param {object} options - options
* @param {string} options.clientId - Client id to distinguish instances if you are using multiple, otherwise keep null if you are using only one instance
* @param {string} options.dataPath - Change the default path for saving session files, default is: "./.wwebjs_auth/"
*/
class LocalAuth extends BaseAuthStrategy {
constructor({ clientId, dataPath } = {}) {
super();
const idRegex = /^[-_w]+$/i;
if (clientId && !idRegex.test(clientId)) {
throw new Error('Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.');
}
this.dataPath = path.resolve(dataPath || './.wwebjs_auth/');
this.clientId = clientId;
}
async beforeBrowserInitialized() {
const puppeteerOpts = this.client.options.puppeteer;
const sessionDirName = this.clientId ? `session-${this.clientId}` : 'session';
const dirPath = path.join(this.dataPath, sessionDirName);
if (puppeteerOpts.userDataDir && puppeteerOpts.userDataDir !== dirPath) {
throw new Error('LocalAuth is not compatible with a user-supplied userDataDir.');
}
fs.mkdirSync(dirPath, { recursive: true });
this.client.options.puppeteer = {
...puppeteerOpts,
userDataDir: dirPath
};
this.userDataDir = dirPath;
}
async logout() {
if (this.userDataDir) {
try {
// 1) First, gracefully shut down the client/browser
if (this.client) {
await this.client.destroy();
}
// 2) Then, remove the session files from disk
await deleteDirectoryWithRetries(this.userDataDir);
console.log('Logout completed successfully. Session directory removed.');
} catch (e) {
console.error(`Logout failed: ${e.message}`);
// throw new Error(`Logout failed: ${e.message}`); // or handle it as needed
}
}
}
}
module.exports = LocalAuth;
How to Use:
To apply this fix, use the patched library from GitHub by installing it directly:
npm install github:Max77788/whatsapp-web.js#fix/localauth-logout
This will pull the updated LocalAuth.js file with the retry mechanism added to the logout method.
Why This Works:
The new implementation includes a maxRetries option for fs.promises.rm() to ensure that session directory removal is retried in case of transient file system issues. This prevents the app from crashing during a manual logout.
If you still face issues, feel free to comment below!