Tencent/matrix · error · IllegalArgumentException
Cannot add the same observer with different lifecycles
Error message
Cannot add the same observer with different lifecycles
What it means
StatefulOwner.checkLifecycle validates that an observer previously registered with one lifecycle owner is not re-registered against a different one. If the same observer instance claims attachment to a different LifecycleOwner (per isAttachedTo) or violates the wrapper-type expectations, it throws IllegalArgumentException to prevent ambiguous lifecycle binding.
Solutions
- Create a new observer instance for each LifecycleOwner instead of sharing one observer across lifecycles.
- Register the observer with the same LifecycleOwner it was originally attached to.
- Remove (unobserve) the observer from its previous owner before re-registering with another one.
Example fix
// before
val shared = object : IStateObserver { ... }
activityALifecycleOwner.let { owner.observeForever(it, shared) }
activityBLifecycleOwner.let { owner.observeForever(it, shared) } // throws
// after
activityBLifecycleOwner.let { owner.observeForever(it, object : IStateObserver { ... }) } Defensive patterns
Strategy: type-guard
Validate before calling
// Track registration per owner
private val registered = mutableMapOf<IStateObserver, LifecycleOwner>()
fun safeObserve(owner: IStatefulOwner, lc: LifecycleOwner, obs: IStateObserver) {
check(registered[obs] == null || registered[obs] === lc) { "observer bound to different lifecycle" }
owner.observeForever(lc, obs); registered[obs] = lc
} Type guard
fun isSameLifecycle(prev: LifecycleOwner?, cur: LifecycleOwner) = prev == null || prev === cur
Try / catch
try {
owner.observeForever(lifecycleOwner, observer)
} catch (e: IllegalArgumentException) {
MatrixLog.w(TAG, "observer already bound to another lifecycle", e)
} Prevention
- Create a fresh IStateObserver instance per LifecycleOwner.
- Never share observer objects across Activities/Fragments.
- Remove observers from their previous owner before re-binding.
When it happens
Trigger: Calling observe/observeForever with the same observer instance but a different LifecycleOwner than the one it was first registered with; checkLifecycle detects the mismatch and throws.
Common situations: Reusing a single IStateObserver object across multiple Activities/Fragments instead of creating a new observer per lifecycle; passing an observer registered on a ProcessLifecycleOwner into an Activity-scoped registration.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- NOT allow to add MultiSourceStatefulOwner as source…
- plugin start, but plugin has been already destroyed
- plugin start, but plugin has been already started
- plugin start, plugin listener is null
- plugin stop, but plugin has been already destroyed
AI-assisted analysis of Tencent/matrix@3b8293bd65 (2026-09-08).
Data as JSON: /api/errors/b18e79105ee75389.
Report an issue: GitHub.
Appendix: source
Thrown at matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/StatefulOwner.kt:120
}
override fun isAttachedTo(owner: LifecycleOwner?) = lifecycleOwner == owner
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun release() {
statefulOwner.removeObserver(observer)
}
}
private fun ObserverWrapper.checkLifecycle(lifecycleOwner: LifecycleOwner?): Boolean {
val broken = if (lifecycleOwner != null) {
isAttachedTo(lifecycleOwner)
} else {
this is AutoReleaseObserverWrapper
}
if (broken) {
throw IllegalArgumentException(
"Cannot add the same observer with different lifecycles"
)
}
return false
}
private enum class State(val dispatch: ((observer: IStateObserver) -> Unit)?) {
INIT(null),
ON({ observer -> observer.on() }),
OFF({ observer -> observer.off() });
}
open class StatefulOwner(val async: Boolean = true) : IStatefulOwner {
@Volatile
private var state = State.INIT
View on GitHub (pinned to 3b8293bd65)