Skip to content

fix: implement session locking to prevent race conditions during session management#2581

Open
jlucaso1 wants to merge 1 commit into
developfrom
fix/signal-session-race
Open

fix: implement session locking to prevent race conditions during session management#2581
jlucaso1 wants to merge 1 commit into
developfrom
fix/signal-session-race

Conversation

@jlucaso1

@jlucaso1 jlucaso1 commented May 21, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Bug Fixes

    • Per-session locking added to prevent concurrent session read/write races, improving message encryption/decryption reliability.
    • Retry and session-recreation flows now perform safe session clears under the new locking to avoid race conditions.
    • Session migration and deletion operations are now executed atomically to prevent inconsistent session state.
  • Chores

    • Storage transaction API enhanced with an isolated-transaction option; tests updated to cover the new paths.

Review Change Stack

@whiskeysockets-bot

whiskeysockets-bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

Thanks for opening this pull request and contributing to the project!

The next step is for the maintainers to review your changes. If everything looks good, it will be approved and merged into the main branch.

In the meantime, anyone in the community is encouraged to test this pull request and provide feedback.

✅ How to confirm it works

If you’ve tested this PR, please comment below with:

Tested and working ✅

This helps us speed up the review and merge process.

📦 To test this PR locally:

# NPM
npm install @whiskeysockets/baileys@WhiskeySockets/Baileys#fix/signal-session-race

# Yarn (v2+)
yarn add @whiskeysockets/baileys@WhiskeySockets/Baileys#fix/signal-session-race

# PNPM
pnpm add @whiskeysockets/baileys@WhiskeySockets/Baileys#fix/signal-session-race

If you encounter any issues or have feedback, feel free to comment as well.

@coderabbitai

coderabbitai Bot commented May 21, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e9b409d8-ea94-4bc9-a492-966b1c016ca6

📥 Commits

Reviewing files that changed from the base of the PR and between f0d33e5 and 9fcf7d5.

📒 Files selected for processing (7)
  • src/Signal/libsignal.ts
  • src/Socket/messages-recv.ts
  • src/Types/Auth.ts
  • src/Types/Signal.ts
  • src/Utils/auth-utils.ts
  • src/__tests__/Signal/lid-mapping.test.ts
  • src/__tests__/Utils/tc-token.test.ts
✅ Files skipped from review due to trivial changes (1)
  • src/Types/Auth.ts

📝 Walkthrough

Walkthrough

This PR adds keyed per-session mutex locking and isolated transaction support, exposes deleteSessionForJid, and migrates Signal encrypt/decrypt/init/migrate/delete and retry cleanup flows to acquire per-session locks and run inside isolated transaction contexts.

Changes

Per-session concurrency control and session deletion

Layer / File(s) Summary
Transaction isolation foundation
src/Types/Auth.ts, src/Utils/auth-utils.ts
SignalKeyStoreWithTransaction gains isolatedTransaction<T>; addTransactionCapability implements it to run work inside a fresh ALS context and commit mutations before returning.
Locking infra and repo API
src/Signal/libsignal.ts, src/Types/Signal.ts
Imports makeKeyedMutex, adds sessionMutex, withSessionLocks, resolveSignalAddress/resolveSessionKey, runIsolated helper, and adds deleteSessionForJid(jid) to SignalRepository.
Encrypt / Decrypt guarded by per-session locks
src/Signal/libsignal.ts
encryptMessage/decryptMessage resolve canonical session key, acquire per-session mutex, and run crypto operations inside runIsolated; pkmsg identity save runs inside the same locked/isolated critical section.
Session deletion and bulk delete under locks
src/Signal/libsignal.ts
Adds deleteSessionForJid (resolve, lock, clear session inside runIsolated) and refactors bulk deleteSession(jids) to resolve keys and perform deletions under withSessionLocks + runIsolated.
Session migration and init under multi-locks
src/Signal/libsignal.ts
injectE2ESession now locks by resolved session key and runs cipher.initOutgoing(...) via runIsolated; migrateSession builds per-device ops (including PN/LID addresses), acquires per-device locks with withSessionLocks, and runs migration inside runIsolated.
Message retry session cleanup using deleteSessionForJid
src/Socket/messages-recv.ts
Four session reset sites (retry recreation, registration-id mismatch, base-key collision, outgoing retry recreation) now call signalRepository.deleteSessionForJid(...) instead of directly mutating authState.keys.
Test mock updates for isolation and deletion APIs
src/__tests__/Signal/lid-mapping.test.ts, src/__tests__/Utils/tc-token.test.ts
Mocks gain isolatedTransaction that executes the provided async callback so test paths using isolated transactions run correctly.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • purpshell

Poem

🐰 Hop-hop, the sessions align,
Locks in paw to keep states fine,
Isolated hops commit with care,
No race, no scramble — just tidy state there,
A little rabbit cheers the guarded line!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: implementing session locking to prevent race conditions in session management, which is the core focus across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/Utils/auth-utils.ts (1)

364-366: ⚡ Quick win

Use err key for error logging per coding guidelines.

The structured logging convention specifies errors should go under err, not error.

Proposed fix
 			} catch (error) {
-				logger.error({ error }, 'isolated transaction failed')
+				logger.error({ err: error }, 'isolated transaction failed')
 				throw error

As per coding guidelines: "Errors should go under err, not error or e."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Utils/auth-utils.ts` around lines 364 - 366, In the catch block that logs
failed isolated transactions, change the structured payload to use the `err` key
instead of `error` so it follows logging guidelines; specifically update the
call to `logger.error` that currently passes `{ error }` (the catch variable
named `error`) alongside the message `'isolated transaction failed'` to instead
pass `{ err: error }` while leaving the message and rethrow unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/__tests__/Signal/lid-mapping.test.ts`:
- Around line 12-14: The mock introduces a new any via the callback type "(work:
() => any)"; change the callback's type to match the real interface by using
Parameters<SignalKeyStoreWithTransaction['isolatedTransaction']>[0] for the work
parameter (i.e., (work:
Parameters<SignalKeyStoreWithTransaction['isolatedTransaction']>[0]) =>
ReturnType<Parameters<SignalKeyStoreWithTransaction['isolatedTransaction']>[0]>
or simply (work:
Parameters<SignalKeyStoreWithTransaction['isolatedTransaction']>[0]) => any to
preserve behavior) so the jest.fn typing for isolatedTransaction aligns with the
SignalKeyStoreWithTransaction signature and remove the new any; keep the
jest.fn<SignalKeyStoreWithTransaction['isolatedTransaction']>(...) wrapper and
adjust or remove the trailing "as any" cast if no longer needed.

In `@src/__tests__/Utils/tc-token.test.ts`:
- Around line 33-35: Replace the explicit any callback in the
isolatedTransaction mock by letting TypeScript infer the callback parameter:
change the mock to use
jest.fn<SignalKeyStoreWithTransaction['isolatedTransaction']>(async (work) =>
await work()) and remove the explicit "(work: () => any)" (and the unnecessary
"as any" cast) so the work parameter type is inferred from
SignalKeyStoreWithTransaction['isolatedTransaction'].

---

Nitpick comments:
In `@src/Utils/auth-utils.ts`:
- Around line 364-366: In the catch block that logs failed isolated
transactions, change the structured payload to use the `err` key instead of
`error` so it follows logging guidelines; specifically update the call to
`logger.error` that currently passes `{ error }` (the catch variable named
`error`) alongside the message `'isolated transaction failed'` to instead pass
`{ err: error }` while leaving the message and rethrow unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 6c63366a-f1f9-4bd1-a1cf-8305e5988066

📥 Commits

Reviewing files that changed from the base of the PR and between 1aee6ed and f0d33e5.

📒 Files selected for processing (7)
  • src/Signal/libsignal.ts
  • src/Socket/messages-recv.ts
  • src/Types/Auth.ts
  • src/Types/Signal.ts
  • src/Utils/auth-utils.ts
  • src/__tests__/Signal/lid-mapping.test.ts
  • src/__tests__/Utils/tc-token.test.ts

Comment thread src/__tests__/Signal/lid-mapping.test.ts Outdated
Comment thread src/__tests__/Utils/tc-token.test.ts Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2 issues found across 7 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/Types/Auth.ts Outdated
Comment thread src/Signal/libsignal.ts Outdated
@jlucaso1 jlucaso1 force-pushed the fix/signal-session-race branch from f0d33e5 to 9fcf7d5 Compare May 21, 2026 04:00
@jlucaso1 jlucaso1 changed the base branch from master to develop May 22, 2026 02:41
@github-actions

github-actions Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

This PR is stale because it has been open for 14 days with no activity. Remove the stale label or comment or this will be closed in 14 days

@github-actions github-actions Bot added the Stale label Jun 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

2 participants