diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt
index 778550a7c4..9693e56ff0 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt
@@ -38,7 +38,6 @@ import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
 import org.matrix.android.sdk.internal.database.query.where
 import org.matrix.android.sdk.internal.di.SessionDatabase
 import org.matrix.android.sdk.internal.session.room.send.LocalEchoEventFactory
-import org.matrix.android.sdk.internal.session.room.send.LocalEchoRepository
 import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProcessor
 import org.matrix.android.sdk.internal.task.TaskExecutor
 import org.matrix.android.sdk.internal.task.configureWith
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt
index 9d003c1ff6..d000bbeb50 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimelineService.kt
@@ -87,7 +87,7 @@ internal class DefaultTimelineService @AssistedInject constructor(@Assisted priv
     }
 
     override fun getTimeLineEventLive(eventId: String): LiveData<Optional<TimelineEvent>> {
-        return LiveTimelineEvent(timelineInput, monarchy, taskExecutor, timelineEventMapper, roomId, eventId)
+        return LiveTimelineEvent(timelineInput, monarchy, taskExecutor.executorScope, timelineEventMapper, roomId, eventId)
     }
 
     override fun getAttachmentMessages(): List<TimelineEvent> {
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LiveTimelineEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LiveTimelineEvent.kt
index 0e9c917b05..3c0f101e11 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LiveTimelineEvent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/LiveTimelineEvent.kt
@@ -20,6 +20,7 @@ import androidx.lifecycle.LiveData
 import androidx.lifecycle.MediatorLiveData
 import androidx.lifecycle.Transformations
 import com.zhuinden.monarchy.Monarchy
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import org.matrix.android.sdk.api.session.events.model.LocalEcho
@@ -29,14 +30,14 @@ import org.matrix.android.sdk.api.util.toOptional
 import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper
 import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
 import org.matrix.android.sdk.internal.database.query.where
-import org.matrix.android.sdk.internal.task.TaskExecutor
+import java.util.concurrent.atomic.AtomicBoolean
 
 /**
  * This class takes care of handling case where local echo is replaced by the synced event in the db.
  */
 internal class LiveTimelineEvent(private val timelineInput: TimelineInput,
                                  private val monarchy: Monarchy,
-                                 private val taskExecutor: TaskExecutor,
+                                 private val coroutineScope: CoroutineScope,
                                  private val timelineEventMapper: TimelineEventMapper,
                                  private val roomId: String,
                                  private val eventId: String)
@@ -45,12 +46,15 @@ internal class LiveTimelineEvent(private val timelineInput: TimelineInput,
 
     private var queryLiveData: LiveData<Optional<TimelineEvent>>? = null
 
+    // If we are listening to local echo, we want to be aware when event is synced
+    private var shouldObserveSync = AtomicBoolean(LocalEcho.isLocalEchoId(eventId))
+
     init {
         buildAndObserveQuery(eventId)
     }
 
     // Makes sure it's made on the main thread
-    private fun buildAndObserveQuery(eventIdToObserve: String) = taskExecutor.executorScope.launch(Dispatchers.Main) {
+    private fun buildAndObserveQuery(eventIdToObserve: String) = coroutineScope.launch(Dispatchers.Main) {
         queryLiveData?.also {
             removeSource(it)
         }
@@ -60,14 +64,15 @@ internal class LiveTimelineEvent(private val timelineInput: TimelineInput,
         )
         queryLiveData = Transformations.map(liveData) { events ->
             events.firstOrNull().toOptional()
-        }
-        queryLiveData?.also {
+        }.also {
             addSource(it) { newValue -> value = newValue }
         }
     }
 
     override fun onLocalEchoSynced(roomId: String, localEchoEventId: String, syncedEventId: String) {
-        if (localEchoEventId == eventId) {
+        if (this.roomId == roomId && localEchoEventId == this.eventId) {
+            timelineInput.listeners.remove(this)
+            shouldObserveSync.set(false)
             // rebuild the query with the new eventId
             buildAndObserveQuery(syncedEventId)
         }
@@ -75,15 +80,14 @@ internal class LiveTimelineEvent(private val timelineInput: TimelineInput,
 
     override fun onActive() {
         super.onActive()
-        // If we are listening to local echo, we want to be aware when event is synced
-        if (LocalEcho.isLocalEchoId(eventId)) {
+        if (shouldObserveSync.get()) {
             timelineInput.listeners.add(this)
         }
     }
 
     override fun onInactive() {
         super.onInactive()
-        if (LocalEcho.isLocalEchoId(eventId)) {
+        if (shouldObserveSync.get()) {
             timelineInput.listeners.remove(this)
         }
     }
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt
index 0b1f67c7b7..adf315a955 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt
@@ -18,6 +18,7 @@ package im.vector.app.features.home.room.detail.timeline.action
 import com.airbnb.mvrx.FragmentViewModelContext
 import com.airbnb.mvrx.MvRxViewModelFactory
 import com.airbnb.mvrx.ViewModelContext
+import com.jakewharton.rxrelay2.BehaviorRelay
 import dagger.Lazy
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
@@ -75,6 +76,8 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
         pillsPostProcessorFactory.create(initialState.roomId)
     }
 
+    private val eventIdObservable = BehaviorRelay.createDefault(initialState.eventId)
+
     @AssistedFactory
     interface Factory {
         fun create(initialState: MessageActionState): MessageActionsViewModel
@@ -90,6 +93,7 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
 
     init {
         observeEvent()
+        observeReactions()
         observePowerLevel()
         observeTimelineEventState()
     }
@@ -135,14 +139,17 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
                 }
     }
 
-    private fun observeReactions(eventId: String) {
+    private fun observeReactions() {
         if (room == null) return
-        room.rx()
-                .liveAnnotationSummary(eventId)
-                .map { annotations ->
-                    EmojiDataSource.quickEmojis.map { emoji ->
-                        ToggleState(emoji, annotations.getOrNull()?.reactionsSummary?.firstOrNull { it.key == emoji }?.addedByMe ?: false)
-                    }
+        eventIdObservable
+                .switchMap { eventId ->
+                    room.rx()
+                            .liveAnnotationSummary(eventId)
+                            .map { annotations ->
+                                EmojiDataSource.quickEmojis.map { emoji ->
+                                    ToggleState(emoji, annotations.getOrNull()?.reactionsSummary?.firstOrNull { it.key == emoji }?.addedByMe ?: false)
+                                }
+                            }
                 }
                 .execute {
                     copy(quickStates = it)
@@ -152,7 +159,7 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
     private fun observeTimelineEventState() {
         selectSubscribe(MessageActionState::timelineEvent, MessageActionState::actionPermissions) { timelineEvent, permissions ->
             val nonNullTimelineEvent = timelineEvent() ?: return@selectSubscribe
-            observeReactions(nonNullTimelineEvent.eventId)
+            eventIdObservable.accept(nonNullTimelineEvent.eventId)
             setState {
                 copy(
                         eventId = nonNullTimelineEvent.eventId,