-
Notifications
You must be signed in to change notification settings - Fork 1.7k
[Bug]: Session restoration has implicit startup race in SessionManager hydration #1889
Description
Bug Description
SessionManager fires async hydration (loadActiveSessions()) in its constructor without awaiting it. ChannelManager.initialize() then immediately passes the unhydrated session manager to PluginManager and starts loading plugins. The in-memory session map may be empty when plugins begin accepting messages, causing getSession() to miss existing persisted sessions.
Steps to Reproduce
- Have an active channel session persisted in the database (e.g., a Telegram user mid-conversation)
- Restart the app
- Send a message via the channel plugin immediately after startup
- Observe that a new session/conversation is created instead of resuming the existing one
Note: this does not reproduce reliably today because shared getDatabase() promise ordering implicitly guarantees hydration completes first. It becomes reproducible if the DB instance is cached or startup order is refactored.
Root Cause
The SessionManager constructor calls this.loadActiveSessions() (an async method) but does not store or await the returned promise. ChannelManager.initialize() instantiates SessionManager and immediately proceeds to create PluginManager and load plugins — no barrier ensures hydration has finished.
The current code is safe only because both loadActiveSessions() and loadEnabledPlugins() internally await getDatabase(), and microtask ordering guarantees the hydration continuation runs first. This is implicit and fragile.
Impact if broken
getSession()returnsnullfor users with existing sessions- Duplicate sessions and conversations are created
- Users lose conversation history after app restarts
- Orphaned DB records accumulate over time
- Tool confirmation callbacks may route to the wrong conversation
Affected Files (fixed in #1888)
src/process/channels/core/SessionManager.ts— constructor fires hydration without storing promisesrc/process/channels/core/ChannelManager.ts— no await on session hydration before plugin setup
Diff
+5 −1 across 2 files (explicit await added, no logic changes)