{"record":{"id":"898c6c7dd3a9c10e","repo":"Tencent/matrix","slug":"not-allow-to-observe-with-destroyed-lifecycle-owne","errorCode":null,"errorMessage":"NOT allow to observe with DESTROYED lifecycle owner","messagePattern":"NOT allow to observe with DESTROYED lifecycle owner","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/StatefulOwner.kt","lineNumber":99,"sourceCode":"\ninterface IMultiSourceOwner {\n    fun addSourceOwner(owner: StatefulOwner)\n    fun removeSourceOwner(owner: StatefulOwner)\n}\n\nprivate open class ObserverWrapper(val observer: IStateObserver, val statefulOwner: StatefulOwner) {\n    open fun isAttachedTo(owner: LifecycleOwner?) = false\n}\n\nprivate class AutoReleaseObserverWrapper constructor(\n    val lifecycleOwner: LifecycleOwner,\n    targetObservable: StatefulOwner,\n    observer: IStateObserver\n) : ObserverWrapper(observer, targetObservable), LifecycleObserver {\n\n    init {\n        if (lifecycleOwner.lifecycle.currentState == Lifecycle.State.DESTROYED) {\n            throw IllegalStateException(\"NOT allow to observe with DESTROYED lifecycle owner\")\n        }\n        lifecycleOwner.lifecycle.addObserver(this)\n    }\n\n    override fun isAttachedTo(owner: LifecycleOwner?) = lifecycleOwner == owner\n\n    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)\n    fun release() {\n        statefulOwner.removeObserver(observer)\n    }\n}\n\nprivate fun ObserverWrapper.checkLifecycle(lifecycleOwner: LifecycleOwner?): Boolean {\n    val broken = if (lifecycleOwner != null) {\n        isAttachedTo(lifecycleOwner)\n    } else {\n        this is AutoReleaseObserverWrapper\n    }","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/Tencent/matrix/blob/3b8293bd65d47eeea7caf1f32a3a5d4d5eab60e7/matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/StatefulOwner.kt#L81-L117","documentation":"Matrix's AutoReleaseObserverWrapper attaches an IStateObserver to a LifecycleOwner's lifecycle. In its init block it checks whether the lifecycle owner's currentState is DESTROYED; observing a destroyed owner is meaningless because the observer would never receive events and the attachment contract forbids it, so it throws IllegalStateException immediately.","triggerScenarios":"Calling IStatefulOwner.observeForever / observe (or any API that wraps the observer in AutoReleaseObserverWrapper) with a LifecycleOwner whose lifecycle.getCurrentState() == Lifecycle.State.DESTROYED, e.g. an Activity or Fragment already destroyed.","commonSituations":"Registering a Matrix observer in a callback that fires after the Activity/Fragment is destroyed (async result delivery, onDestroy cleanup paths, work finishing after configuration change), or caching a LifecycleOwner reference and using it after teardown.","solutions":["Check lifecycleOwner.lifecycle.currentState != Lifecycle.State.DESTROYED before registering the observer.","Register the observer earlier in the owner's lifecycle (e.g. onCreate/onStart) instead of in late or async callbacks.","Skip registration when the owner is destroyed instead of observing, e.g. wrap the observe call in a state check."],"exampleFix":"// before\nowner.observeForever(lifecycleOwner, myObserver)\n// after\nif (lifecycleOwner.lifecycle.currentState != Lifecycle.State.DESTROYED) {\n    owner.observeForever(lifecycleOwner, myObserver)\n}","handlingStrategy":"validation","validationCode":"fun canObserve(owner: LifecycleOwner) = owner.lifecycle.currentState != Lifecycle.State.DESTROYED","typeGuard":"fun LifecycleOwner.isAliveForObserving() = lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED) && lifecycle.currentState != Lifecycle.State.DESTROYED","tryCatchPattern":"try {\n    owner.observeForever(lifecycleOwner, observer)\n} catch (e: IllegalStateException) {\n    MatrixLog.w(TAG, \"owner already destroyed, skip observe\", e)\n}","preventionTips":["Always register lifecycle-observers in onCreate/onStart of the Activity/Fragment.","Check currentState before any observe call on a cached LifecycleOwner.","Avoid delivering async results into registration code after the owner may be destroyed."],"tags":["android","lifecycle","illegal-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"3b8293bd65d47eeea7caf1f32a3a5d4d5eab60e7","analyzedAt":"2026-09-08T08:01:39.722Z","contentChangedAt":"2026-09-08T08:01:39.722Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}