fix(baileys): resolve incoming message events not working after reconnection by muriloleal13 · Pull Request #2186 · EvolutionAPI/evolution-api · GitHub
Skip to content

fix(baileys): resolve incoming message events not working after reconnection#2186

Merged
DavidsonGomes merged 1 commit intoEvolutionAPI:developfrom
muriloleal13:fix/baileys-message-processor-reconnection
Nov 7, 2025
Merged

fix(baileys): resolve incoming message events not working after reconnection#2186
DavidsonGomes merged 1 commit intoEvolutionAPI:developfrom
muriloleal13:fix/baileys-message-processor-reconnection

Conversation

@muriloleal13
Copy link
Copy Markdown
Contributor

@muriloleal13 muriloleal13 commented Nov 4, 2025

Fix: Incoming message events not working after reconnection

🐛 Problem Description

After disconnecting an instance (using /instance/logout) and reconnecting (using /instance/connect), incoming message events stop being triggered, while outgoing message events continue to work normally.

Affected Scenarios:

  • Restart instance (/instance/restart) - Works correctly
  • Logout + Connect (/instance/logout/instance/connect) - Broken
  • Automatic reconnection - Works correctly

User Impact:

  • Webhooks for incoming messages are not triggered after manual reconnection
  • Chatbot integrations (OpenAI, Dify, Typebot, etc.) stop receiving messages
  • Outgoing messages continue to work normally (misleading behavior)

🔍 Root Cause Analysis

The issue is in the BaileysMessageProcessor lifecycle management:

  1. Initial state: When an instance is created, messageProcessor.mount() is called in the constructor, creating an RxJS Subject and subscription
  2. Logout trigger: /instance/logoutlogoutInstance()messageProcessor.onDestroy()messageSubject.complete()
  3. Subject completed: Once complete() is called on an RxJS Subject, it becomes permanently closed and silently ignores all future next() calls
  4. Reconnection: /instance/connectconnectToWhatsapp()createClient() → event handlers are set up
  5. Messages arrive: Incoming messages trigger events['messages.upsert']messageProcessor.processMessage()messageSubject.next()SILENTLY IGNORED (Subject is completed)
  6. No webhooks: Since messages never flow through the processor, no webhooks/events are triggered

Why outgoing messages work:

Outgoing messages bypass the messageProcessor entirely and call sendDataWebhook() directly.

Why restart works:

The restartInstance() method closes the WebSocket and recreates the client WITHOUT calling logoutInstance(), so onDestroy() is never called and the messageProcessor remains functional.

✅ Solution

This PR implements a defensive approach with auto-recovery:

Changes Made:

1. baileysMessage.processor.ts - Add cleanup and auto-recovery in mount()

mount({ onMessageReceive }: MountProps) {
  // Cleanup old subscription to prevent memory leaks
  if (this.subscription && !this.subscription.closed) {
    this.subscription.unsubscribe();
  }

  // Auto-recovery: Recreate Subject if it was completed
  if (this.messageSubject.closed) {
    this.processorLogs.warn('MessageSubject was closed, recreating...');
    this.messageSubject = new Subject<{...}>();
  }
  
  // ... rest of the code
}

Benefits:

  • ✅ Prevents memory leaks from multiple subscriptions
  • ✅ Auto-recovers if Subject is completed (defensive programming)
  • ✅ Adds informative logging for debugging

2. whatsapp.baileys.service.ts - Remount processor on connection

public async connectToWhatsapp(number?: string): Promise<WASocket> {
  try {
    this.loadChatwoot();
    this.loadSettings();
    this.loadWebhook();
    this.loadProxy();

    // Remount messageProcessor to ensure subscription is active
    this.messageProcessor.mount({
      onMessageReceive: this.messageHandle['messages.upsert'].bind(this),
    });

    return await this.createClient(number);
  } catch (error) {
    this.logger.error(error);
    throw new InternalServerErrorException(error?.toString());
  }
}

Benefits:

  • ✅ Ensures subscription is active after every connection/reconnection
  • ✅ Works with the auto-recovery mechanism in mount()

🧪 Testing

Manual Testing Steps:

  1. Create an instance: POST /instance/create
  2. Connect: POST /instance/connect/{instanceName}
  3. Verify incoming messages trigger webhooks ✅
  4. Logout: DELETE /instance/logout/{instanceName}
  5. Reconnect: POST /instance/connect/{instanceName}
  6. Send a message to the instance
  7. Expected: Webhook is triggered ✅
  8. Before fix: Webhook is NOT triggered ❌

Tested Scenarios:

  • ✅ Create → Connect → Logout → Reconnect → Receive message
  • ✅ Multiple reconnections in sequence
  • ✅ Restart instance (ensure it still works)
  • ✅ Automatic reconnection after connection drop
  • ✅ Multiple instances in parallel

📊 Performance Impact

  • Memory: Negligible (Subject creation is ~0.1ms, properly garbage collected)
  • CPU: Minimal overhead from cleanup checks
  • Behavior: No breaking changes, only fixes broken functionality

🔄 Backward Compatibility

  • ✅ No breaking changes
  • ✅ No API changes
  • ✅ No configuration changes required
  • ✅ Works with all existing integrations (Baileys, Business API, Evolution)

📝 Additional Notes

  • This fix follows RxJS best practices (completed Subjects should be discarded and recreated)
  • The solution is defensive: even if complete() is called elsewhere in the future, the system auto-recovers
  • Logging was added to help debug similar issues in the future

🔗 Related Issues

This fix resolves the issue where users reported that after disconnecting and reconnecting instances, they stop receiving incoming message notifications/events, while outgoing messages continue to work normally.


Checklist:

  • Code follows project style guidelines (ESLint + Prettier)
  • Commit follows Conventional Commits format
  • Changes are backward compatible
  • Manual testing completed successfully
  • No breaking changes introduced

Summary by Sourcery

Fix incoming message events not being handled after manual logout and reconnect by adding cleanup and auto-recovery in the message processor and remounting it on each connection

Bug Fixes:

  • Unsubscribe stale RxJS subscriptions and recreate closed Subjects in BaileysMessageProcessor.mount to restore incoming message processing
  • Remount the message processor in connectToWhatsapp to reinitialize incoming message event handlers after reconnection

…nection

- Add cleanup logic in mount() to prevent memory leaks from multiple subscriptions

- Recreate messageSubject if it was completed during logout

- Remount messageProcessor in connectToWhatsapp() to ensure subscription is active after reconnection

This fixes the issue where incoming message events stop working after logout and reconnect, while outgoing message events continue to work normally.

The root cause was that onDestroy() calls complete() on the RxJS Subject, making it permanently closed. When reconnecting, the Subject would silently ignore all new messages.

The fix ensures that:

1. Old subscriptions are properly cleaned up before creating new ones

2. If the Subject is closed, a new one is created automatically

3. The messageProcessor is remounted on every connection to ensure active subscription
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Nov 4, 2025

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • Consider moving the messageProcessor.mount() call to after the Baileys socket emits its open event, so you don’t miss any messages that arrive during the initial client handshake.
  • Simplify the Subject lifecycle by always recreating messageSubject at the start of mount() (after unsubscribing) rather than conditionally checking closed, which makes the reset behavior more explicit.
  • Add a debug log when unsubscribing the old subscription to help trace cleanup operations and ensure no dangling subscriptions remain after reconnect.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider moving the messageProcessor.mount() call to after the Baileys socket emits its open event, so you don’t miss any messages that arrive during the initial client handshake.
- Simplify the Subject lifecycle by always recreating messageSubject at the start of mount() (after unsubscribing) rather than conditionally checking closed, which makes the reset behavior more explicit.
- Add a debug log when unsubscribing the old subscription to help trace cleanup operations and ensure no dangling subscriptions remain after reconnect.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@gabriel-sa-dev
Copy link
Copy Markdown

Aprovação necessária, o app está quebrando exatamente nessa parte

@Jeferson-Ramos-Einov
Copy link
Copy Markdown
Contributor

@DavidsonGomes DavidsonGomes changed the base branch from main to develop November 7, 2025 17:37
@DavidsonGomes DavidsonGomes merged commit 139ad9b into EvolutionAPI:develop Nov 7, 2025
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants