@@ -284,7 +284,7 @@ export class BaileysStartupService extends ChannelStartupService {
284284 }
285285
286286 public async logoutInstance ( ) {
287- // Mark instance as deleting to prevent reconnection attempts
287+ // Mark instance as deleting to prevent reconnection attempts.
288288 this . isDeleting = true ;
289289 this . endSession = true ;
290290
@@ -294,18 +294,27 @@ export class BaileysStartupService extends ChannelStartupService {
294294 try {
295295 await this . client . logout ( 'Log out instance: ' + this . instanceName ) ;
296296 } catch ( error ) {
297- this . logger . error ( { message : 'Error during logout' , error } ) ;
297+ // Downgraded to warn: logout failures here are recoverable — the
298+ // credential cleanup below still runs and the DB row is forced to 'close'.
299+ this . logger . warn (
300+ `logoutInstance: client.logout() failed (${ ( error as Error ) ?. message } ), proceeding with credential cleanup` ,
301+ ) ;
298302 }
299303
300- // Improved socket cleanup
304+ // Improved socket cleanup.
301305 try {
302306 this . client . ws ?. close ( ) ;
303307 this . client . end ( new Error ( 'Instance logout' ) ) ;
304- } catch ( error ) {
305- this . logger . error ( { message : 'Error during socket cleanup' , error } ) ;
308+ } catch {
309+ // ignore — ws may already be closed
306310 }
307311 }
308312
313+ // Force the in-memory connection state to 'close' so any concurrent reader
314+ // observes the post-logout state immediately, even if the DB update below
315+ // is delayed.
316+ this . stateConnection = { state : 'close' , statusReason : 401 } ;
317+
309318 const db = this . configService . get < Database > ( 'DATABASE' ) ;
310319 const cache = this . configService . get < CacheConf > ( 'CACHE' ) ;
311320 const provider = this . configService . get < ProviderSession > ( 'PROVIDER' ) ;
@@ -332,6 +341,11 @@ export class BaileysStartupService extends ChannelStartupService {
332341 if ( sessionExists ) {
333342 await this . prismaRepository . session . delete ( { where : { sessionId : this . instanceId } } ) ;
334343 }
344+
345+ await this . prismaRepository . instance . update ( {
346+ where : { id : this . instanceId } ,
347+ data : { connectionStatus : 'close' } ,
348+ } ) ;
335349 }
336350
337351 public async getProfileName ( ) {
@@ -479,7 +493,9 @@ export class BaileysStartupService extends ChannelStartupService {
479493 }
480494
481495 const statusCode = ( lastDisconnect ?. error as Boom ) ?. output ?. statusCode ;
482- const codesToNotReconnect = [ DisconnectReason . loggedOut , DisconnectReason . forbidden , 402 , 406 ] ;
496+ // 408 = request timeout — added per #2501 to avoid reconnect loops on
497+ // transient network drops where the server returned a 408 in the close.
498+ const codesToNotReconnect = [ DisconnectReason . loggedOut , DisconnectReason . forbidden , 402 , 406 , 408 ] ;
483499
484500 // FIX: Do not reconnect if it's the initial connection (waiting for QR code)
485501 // This prevents infinite loop that blocks QR code generation
@@ -542,6 +558,10 @@ export class BaileysStartupService extends ChannelStartupService {
542558 }
543559
544560 if ( connection === 'open' ) {
561+ if ( ! this . client ?. user ?. id ) {
562+ this . logger . warn ( 'connectionUpdate: connection open but client.user is undefined, skipping' ) ;
563+ return ;
564+ }
545565 this . instance . wuid = this . client . user . id . replace ( / : \d + / , '' ) ;
546566 try {
547567 const profilePic = await this . profilePicture ( this . instance . wuid ) ;
0 commit comments