pedroslopez / whatsapp-web.js

A WhatsApp client library for NodeJS that connects through the WhatsApp Web browser app
https://wwebjs.dev
Apache License 2.0
15.6k stars 3.72k forks source link

Error: EBUSY: resource busy or locked #3072

Open justoverclockl opened 5 months ago

justoverclockl commented 5 months ago

Is there an existing issue for this?

Describe the bug

N.B. this not happen with previous versions of WWEBJS...happen with exodus package

I can get the qrcode and pairing code correctly, but after a qrcode scan i get

...\server\node_modules\whatsapp-web.js\src\authStrategies\LocalAuth.js:47
            await fs.promises.rm(this.userDataDir, { recursive: true, force: true })
            ^
Error: Error: EBUSY: resource busy or locked, unlink '...\server\.wwebjs_auth\session-adminSession\Default\chrome_debug.log'
    at ...\server\node_modules\whatsapp-web.js\src\authStrategies\LocalAuth.js:49:27
    at LocalAuth.logout (...\server\node_modules\whatsapp-web.js\src\authStrategies\LocalAuth.js:47:13)
    at ...\server\node_modules\whatsapp-web.js\src\Client.js:345:17

this is my client:

const authStrategy = new LocalAuth({
      clientId: 'adminSession',
    });

this.client = new Client({
      authStrategy,
      webVersion: '2.2412.50',
      webVersionCache: {
        remotePath:
          'https://raw.githubusercontent.com/wppconnect-team/wa-version/main/html/2.2412.50.html',
        type: 'remote',
      },
      takeoverOnConflict: true,
      puppeteer: {
        headless: true,
        args: ['--no-sandbox', '--disable-setuid-sandbox'],
      },
    });

Expected behavior

as previous versions, i shouldn't get this error and the phone will be paired correctly.

Steps to Reproduce the Bug or Issue

  1. on Windows, start the server
  2. request qr code
  3. scan qrcode
  4. get the error
...\server\node_modules\whatsapp-web.js\src\authStrategies\LocalAuth.js:47
            await fs.promises.rm(this.userDataDir, { recursive: true, force: true })
            ^
Error: Error: EBUSY: resource busy or locked, unlink '...\server\.wwebjs_auth\session-adminSession\Default\chrome_debug.log'
    at ...\server\node_modules\whatsapp-web.js\src\authStrategies\LocalAuth.js:49:27
    at LocalAuth.logout (...\server\node_modules\whatsapp-web.js\src\authStrategies\LocalAuth.js:47:13)
    at ...\server\node_modules\whatsapp-web.js\src\Client.js:345:17

Relevant Code

seems that the problem is here (based on che stack error)

async logout() { if (this.userDataDir) { await fs.promises.rm(this.userDataDir, { recursive: true, force: true }) .catch((e) => { throw new Error(e); }); } }

Browser Type

Chromium

WhatsApp Account Type

WhatsApp Business

Does your WhatsApp account have multidevice enabled?

No, I am not using Multi Device

Environment

OS: Windows whatsapp-web.js version: "whatsapp-web.js": "github:pedroslopez/whatsapp-web.js#webpack-exodus" node version: 18.17.1 and 20.12.2

Additional context

No response

claudiogg88 commented 5 months ago

any solution?

sauqi28 commented 5 months ago

any solution?

note yet, i have same problem

aangwie commented 5 months ago

any solution?

Try This. Open Constants.js at util folder, change this code WebVersion : 2.2410.1, webVersionCache : { type : 'local' },

With This webVersion: '2.2410.1', webVersionCache: { type: 'remote', remotePath : 'https://raw.githubusercontent.com/wppconnect-team/wa-version/main/html/2.2410.1.html', },

BernetteGunasekaran commented 5 months ago

try this ,its working on windows

webVersion: '2.2322.15', webVersionCache: { type: 'remote', remotePath: 'https://raw.githubusercontent.com/wppconnect-team/wa-version/main/html/2.2412.54.html',

claudiogg88 commented 5 months ago

I deleted all my messages and it didn't give any more errors

justoverclockl commented 5 months ago

try this ,its working on windows

webVersion: '2.2322.15', webVersionCache: { type: 'remote', remotePath: 'https://raw.githubusercontent.com/wppconnect-team/wa-version/main/html/2.2412.54.html',

not work at all...same error for me

maaelphd commented 5 months ago

try this ,its working on windows

webVersion: '2.2322.15', webVersionCache: { type: 'remote', remotePath: 'https://raw.githubusercontent.com/wppconnect-team/wa-version/main/html/2.2412.54.html',

This version work for me, i was receving the error: "Node with given id does not belong to the document" When i checked the Constants.js file it was using the version "2.2410.1", Looking on "https://github.com/wppconnect-team/wa-version/tree/main/html", looks like this versions is not maintened anymore. Change to this new version works fine. However, it is a bit annoying to have to check the versions frequently, but at the moment it is working now!

justoverclockl commented 5 months ago

Why closed????????

No response as always.....what a policy

rizki5411 commented 5 months ago

anyone can fix it?

justoverclockl commented 5 months ago

anyone can fix it?

no one will take care of issues (this is my experience so far). So maybe you need to wait for another version that address this (if you're lucky).

If this can help you this happen to me when i migrate to exodus...previous versions works....(for now)

erenn44 commented 5 months ago

anyone can fix it?

claudiogg88 commented 5 months ago

anyone can fix it?

I was able to resolve it by clearing all messages from the app on my phone

MarcosWandenkolk commented 5 months ago

Modify the logout() function in your Client.js as follows:

   async logout() {
        await this.pupPage.evaluate(() => {
            return window.Store.AppState.logout();
        });

    await this.pupPage.waitForFunction(() => !(window.Store.isLogoutInProgress), { timeout: 20000 });

        let maxDelay = 0;
        while (this.pupBrowser.isConnected() && (maxDelay < 10)) { // waits a maximum of 1 second before calling the AuthStrategy
            await new Promise(resolve => setTimeout(resolve, 100));
            maxDelay++; 
        }

        await this.authStrategy.logout();
    }

For more details see: https://github.com/pedroslopez/whatsapp-web.js/pull/2661/commits/6d68da43ee1a327c88bc8f1c770794bcd9324ea9

MrJmpl3 commented 5 months ago

I think the problem is here: https://github.com/pedroslopez/whatsapp-web.js/blob/cd566f28b9957d58dbd470470f6e2fe018808db3/src/Client.js#L345

Why the logout function delete the user folder without close the browser before?

jenilghevariya09 commented 4 months ago

I have the same problem did anyone get the fix?

max-programming commented 4 months ago

This is somehow related to #3173 When you log out, you will notice the ready event is being fired and according to the issue, the authenticated event is also being fired

jenilghevariya09 commented 4 months ago

Temporary Fix for Preventing User Session Deletion on Logout

For those experiencing issues with user sessions being deleted upon logout in whatsapp-web.js, you can implement a temporary fix by modifying the LocalAuth.js file.

Open the file located at:

node_modules\whatsapp-web.js\src\authStrategies\LocalAuth.js

Comment Out Session Deletion Code

Find the logout method and comment out the code that deletes the session folder:

async logout() {
    // if (this.userDataDir) {
    //     await fs.promises.rm(this.userDataDir, { recursive: true, force: true })
    //         .catch((e) => {
    //             throw new Error(e);
    //         });
    // }
    console.log('==========> logout');
}

Delete Session Folder Manually on Disconnected EventInstead of deleting the session folder on logout, delete it when a disconnected event is fired with the conditions reason == 'NAVIGATION' || reason == 'LOGOUT'.

Add the following code to handle the disconnected event:

client.on("disconnected", async (reason) => {
    await client.destroy();
    if (reason == 'NAVIGATION' || reason == 'LOGOUT') {
        const folderPath = path.join(__dirname, `../../../.wwebjs_auth/session-${userId}`);
        fs.rm(folderPath, { recursive: true, force: true }, (err) => {
            if (err) {
                console.log(`Error deleting folder: ${err.message}`);
            } else {
                console.log('Folder deleted successfully');
            }
        });
    }
});

This will prevent the session folder from being deleted automatically on logout and will ensure it is deleted only when necessary.

rizki5411 commented 4 months ago

Temporary Fix for Preventing User Session Deletion on Logout

For those experiencing issues with user sessions being deleted upon logout in whatsapp-web.js, you can implement a temporary fix by modifying the LocalAuth.js file.

Open the file located at:

node_modules\whatsapp-web.js\src\authStrategies\LocalAuth.js

Comment Out Session Deletion Code

Find the logout method and comment out the code that deletes the session folder:

async logout() {
    // if (this.userDataDir) {
    //     await fs.promises.rm(this.userDataDir, { recursive: true, force: true })
    //         .catch((e) => {
    //             throw new Error(e);
    //         });
    // }
    console.log('==========> logout');
}

Delete Session Folder Manually on Disconnected EventInstead of deleting the session folder on logout, delete it when a disconnected event is fired with the conditions reason == 'NAVIGATION' || reason == 'LOGOUT'.

Add the following code to handle the disconnected event:

client.on("disconnected", async (reason) => {
    await client.destroy();
    if (reason == 'NAVIGATION' || reason == 'LOGOUT') {
        const folderPath = path.join(__dirname, `../../../.wwebjs_auth/session-${userId}`);
        fs.rm(folderPath, { recursive: true, force: true }, (err) => {
            if (err) {
                console.log(`Error deleting folder: ${err.message}`);
            } else {
                console.log('Folder deleted successfully');
            }
        });
    }
});

This will prevent the session folder from being deleted automatically on logout and will ensure it is deleted only when necessary.

please how to get ${userId} ?

jenilghevariya09 commented 4 months ago

Temporary Fix for Preventing User Session Deletion on Logout For those experiencing issues with user sessions being deleted upon logout in whatsapp-web.js, you can implement a temporary fix by modifying the LocalAuth.js file. Open the file located at: node_modules\whatsapp-web.js\src\authStrategies\LocalAuth.js Comment Out Session Deletion Code Find the logout method and comment out the code that deletes the session folder:

async logout() {
    // if (this.userDataDir) {
    //     await fs.promises.rm(this.userDataDir, { recursive: true, force: true })
    //         .catch((e) => {
    //             throw new Error(e);
    //         });
    // }
    console.log('==========> logout');
}

Delete Session Folder Manually on Disconnected EventInstead of deleting the session folder on logout, delete it when a disconnected event is fired with the conditions reason == 'NAVIGATION' || reason == 'LOGOUT'. Add the following code to handle the disconnected event:

client.on("disconnected", async (reason) => {
    await client.destroy();
    if (reason == 'NAVIGATION' || reason == 'LOGOUT') {
        const folderPath = path.join(__dirname, `../../../.wwebjs_auth/session-${userId}`);
        fs.rm(folderPath, { recursive: true, force: true }, (err) => {
            if (err) {
                console.log(`Error deleting folder: ${err.message}`);
            } else {
                console.log('Folder deleted successfully');
            }
        });
    }
});

This will prevent the session folder from being deleted automatically on logout and will ensure it is deleted only when necessary.

please how to get ${userId} ?

basically here userId is clientId.

authStrategy: new LocalAuth({
                clientId: userId, 
            }),

use your clientId instead of it.

gilney-canaltelecom commented 2 months ago

This is still happening on 1.2.6...

error1

code1

It seems like the lib is calling logout on page change, which means its trying to delete puppeteer' data while the browser is still open, which causes the error...

I guess one option would be to stop the browser, call logout and then start it all over again!?

patricksousamacedo commented 6 days ago

Temporary Fix for Preventing User Session Deletion on Logout

For those experiencing issues with user sessions being deleted upon logout in whatsapp-web.js, you can implement a temporary fix by modifying the LocalAuth.js file.

Open the file located at:

node_modules\whatsapp-web.js\src\authStrategies\LocalAuth.js

Comment Out Session Deletion Code

Find the logout method and comment out the code that deletes the session folder:

async logout() {
    // if (this.userDataDir) {
    //     await fs.promises.rm(this.userDataDir, { recursive: true, force: true })
    //         .catch((e) => {
    //             throw new Error(e);
    //         });
    // }
    console.log('==========> logout');
}

Delete Session Folder Manually on Disconnected EventInstead of deleting the session folder on logout, delete it when a disconnected event is fired with the conditions reason == 'NAVIGATION' || reason == 'LOGOUT'.

Add the following code to handle the disconnected event:

client.on("disconnected", async (reason) => {
    await client.destroy();
    if (reason == 'NAVIGATION' || reason == 'LOGOUT') {
        const folderPath = path.join(__dirname, `../../../.wwebjs_auth/session-${userId}`);
        fs.rm(folderPath, { recursive: true, force: true }, (err) => {
            if (err) {
                console.log(`Error deleting folder: ${err.message}`);
            } else {
                console.log('Folder deleted successfully');
            }
        });
    }
});

This will prevent the session folder from being deleted automatically on logout and will ensure it is deleted only when necessary.


This worked for me. I commented out the code block in the LocalAuth.js file and adapted it to 'client.on('disconnected', async (reason: string)'. I am sending my code below so that you have a reference. Please disregard the comments in Portuguese in my code.


whatsappService.ts

import { Client, LocalAuth } from 'whatsapp-web.js';

import qrcode from 'qrcode-terminal';

import path from 'path';
import fs from 'fs';

const clients: { [userId: string]: Client } = {};
const clientReady: { [userId: string]: Promise<void> } = {};

function initializeClient(userId: string) {
  if (clients[userId]) {
    console.log(`Cliente já existe para o usuário ${userId}`);
    return clients[userId];
  }

  const client = new Client({
    puppeteer: {
      headless: true,
    },
    authStrategy: new LocalAuth({ clientId: `session-${userId}` }),
  });

  clientReady[userId] = new Promise((resolve, reject) => {
    client.on('ready', () => {
      console.log(`WhatsApp está pronto para o usuário ${userId}`);
      resolve();
    });

    client.on('auth_failure', (msg) => {
      console.error(`Falha na autenticação para o usuário ${userId}:`, msg);
      reject(new Error('Falha na autenticação'));
    });
  });

  client.on('qr', (qr) => {
    console.log(`Exibindo QR Code para o usuário ${userId}`);
    qrcode.generate(qr, { small: true });
  });

  client.on('disconnected', async (reason: string) => {
    console.log(`Cliente desconectado para o usuário ${userId}:`, reason);

    try {
      // Destrói o cliente para liberar recursos
      await client.destroy();
      console.log(`Cliente destruído para o usuário ${userId}`);
    } catch (err) {
      if (err.code === 'EBUSY') {
        console.warn(`Erro EBUSY ao destruir cliente para o usuário ${userId}. Recurso ocupado ou bloqueado.`);
        // Aguarda um curto período e tenta novamente
        await new Promise((resolve) => setTimeout(resolve, 1000));
        try {
          console.log(`Tentando destruir novamente o cliente para o usuário ${userId}`);
          await client.destroy();
        } catch (retryErr) {
          console.warn(`Tentativa final de destruir cliente para o usuário ${userId} falhou:`, retryErr);
        }
      } else {
        console.warn(`Erro inesperado ao destruir cliente para o usuário ${userId}:`, err);
      }
    }

    // Verifica se a desconexão foi causada por logout ou navegação
    if (reason === 'NAVIGATION' || reason === 'LOGOUT') {
      const folderPath = path.join(__dirname, `../../../.wwebjs_auth/session-${userId}`);
      fs.rm(folderPath, { recursive: true, force: true }, (err) => {
        if (err) {
          console.log(`Erro ao excluir a pasta da sessão para o usuário ${userId}: ${err.message}`);
        } else {
          console.log(`Pasta da sessão excluída com sucesso para o usuário ${userId}`);
        }
      });
    }

    // Remove referências do cliente
    delete clients[userId];
    delete clientReady[userId];

    // Reinicializa o cliente para permitir reconexão
    console.log(`Reinicializando cliente para o usuário ${userId}`);
    initializeClient(userId);
  });

  client.on('authenticated', () => {
    console.log(`Autenticado com sucesso para o usuário ${userId}`);
  });

  client.initialize();
  clients[userId] = client;
  return client;
}

export async function sendMessage(userId: string, number: string, message: string) {
  try {
    const client = initializeClient(userId);

    // Aguarda o cliente ficar pronto antes de enviar mensagens
    if (!clientReady[userId]) {
      console.log(`Cliente para o usuário ${userId} ainda está inicializando.`);
      throw new Error(`Cliente não está pronto para o usuário ${userId}.`);
    }

    await clientReady[userId];
    const formattedNumber = `${number}@c.us`;
    await client.sendMessage(formattedNumber, message);
    console.log(`Mensagem enviada para ${number} pelo usuário ${userId}`);
  } catch (error) {
    console.error(`Erro ao enviar mensagem para ${number} pelo usuário ${userId}:`, error);
  }
}

SendWhatsAppMessagesService.ts


import prismaClient from "../../prisma";
import { sendMessage } from "./whatsappService";

class SendWhatsAppMessagesService {
  async execute(userId: string) { // Recebe o userId do usuário logado
    try {
      // Filtra os cards que pertencem ao usuário logado e têm whats_send como true
      const cards = await prismaClient.card.findMany({
        where: {
          user_id: userId, // Verifica se o card pertence ao usuário logado
          whats_send: true, // Verifica se o card está marcado para envio
        },
      });

      // Itera sobre os cards filtrados e envia as mensagens
      for (const card of cards) {
        if (card.whats_number && card.whats_message) {
          await sendMessage(userId, card.whats_number, card.whats_message); // Envia a mensagem
        }
      }

      console.log(`Mensagens enviadas com sucesso para o usuário ${userId}!`);
    } catch (error) {
      console.error(`Erro ao enviar mensagens para o usuário ${userId}:`, error);
    }
  }
}

export { SendWhatsAppMessagesService };

SendWhatsAppMessagesController.ts


import { Request, Response } from "express";
import { SendWhatsAppMessagesService } from "../../services/whatsapp/SendWhatsAppMessagesService"; 

class SendWhatsAppMessagesController {
  async handle(request: Request, response: Response) {
    const user_id = request.user_id; 

    const sendWhatsAppMessagesService = new SendWhatsAppMessagesService();

    // Executa o serviço de envio de mensagens
    await sendWhatsAppMessagesService.execute(user_id);

    return response.json({ message: "Mensagens enviadas com sucesso!" });
  }
}

export { SendWhatsAppMessagesController };