{"record":{"id":"40b8fbdbd86154fc","repo":"DrKLO/Telegram","slug":"called-removedetachedview-with-a-view-which-is-not","errorCode":null,"errorMessage":"Called removeDetachedView with a view which is not flagged as tmp detached.{vh}","messagePattern":"Called removeDetachedView with a view which is not flagged as tmp detached\\.(.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"TMessagesProj/src/main/java/androidx/recyclerview/widget/RecyclerView.java","lineNumber":4349,"sourceCode":"        }\n        into[0] = minPositionPreLayout;\n        into[1] = maxPositionPreLayout;\n    }\n\n    private boolean didChildRangeChange(int minPositionPreLayout, int maxPositionPreLayout) {\n        findMinMaxChildLayoutPositions(mMinMaxLayoutPositions);\n        return mMinMaxLayoutPositions[0] != minPositionPreLayout\n                || mMinMaxLayoutPositions[1] != maxPositionPreLayout;\n    }\n\n    @Override\n    protected void removeDetachedView(View child, boolean animate) {\n        ViewHolder vh = getChildViewHolderInt(child);\n        if (vh != null) {\n            if (vh.isTmpDetached()) {\n                vh.clearTmpDetachFlag();\n            } else if (!vh.shouldIgnore()) {\n                throw new IllegalArgumentException(\"Called removeDetachedView with a view which\"\n                        + \" is not flagged as tmp detached.\" + vh + exceptionLabel());\n            }\n        }\n\n        // Clear any android.view.animation.Animation that may prevent the item from\n        // detaching when being removed. If a child is re-added before the\n        // lazy detach occurs, it will receive invalid attach/detach sequencing.\n        child.clearAnimation();\n\n        dispatchChildDetached(child);\n        super.removeDetachedView(child, animate);\n    }\n\n    /**\n     * Returns a unique key to be used while handling change animations.\n     * It might be child's position or stable id depending on the adapter type.\n     */\n    long getChangedHolderKey(ViewHolder holder) {","sourceCodeStart":4331,"sourceCodeEnd":4367,"githubUrl":"https://github.com/DrKLO/Telegram/blob/45ab8f4308496e1f01026a97fcdb0d58a5274474/TMessagesProj/src/main/java/androidx/recyclerview/widget/RecyclerView.java#L4331-L4367","documentation":"RecyclerView.removeDetachedView overrides ViewGroup.removeDetachedView and asserts that a child being removed is either marked as temporarily detached (vh.isTmpDetached()) or explicitly flagged to ignore (shouldIgnore()). If neither holds, it throws IllegalArgumentException. The temporary-detach flag is an internal invariant RecyclerView sets when it briefly detaches a view during scrap/recycle bookkeeping; an externally-removed view lacking that flag indicates the detach protocol was bypassed, which would corrupt recycling state.","triggerScenarios":"Externally calling ViewGroup.removeView / removeDetachedView on a RecyclerView child instead of going through the LayoutManager/Recycler API; a LayoutManager that manually detaches views without the tmp-detach flag and then RecyclerView later tries to remove them; nested RecyclerView or nested scrolling components that reach into the parent's view tree.","commonSituations":"Mixing manual ViewGroup view manipulation with RecyclerView; a third-party container or animation library that pulls views out of the RecyclerView; a custom LayoutManager misusing addDisappearingView/scrap attach calls; very old appcompat or RecyclerView version with a known regression on this path.","solutions":["Do not call removeView/removeDetachedView on RecyclerView children directly — use the LayoutManager (removeAndRecycleView / removeAndRecycleViewAt) or let RecyclerView manage its own children.","Audit any custom LayoutManager to ensure it only detaches views via LayoutManager.detachViewAt (which sets the tmp-detach flag) and reattaches before layout completes.","If a third-party animation/container library manipulates RecyclerView children, replace it with an ItemAnimator or wrap the manipulation so it sets the proper flags.","Update androidx.recyclerview to the latest stable version — several historical regressions in detach bookkeeping have been fixed upstream."],"exampleFix":"// before: manually removing a RecyclerView child\nView child = recyclerView.getChildAt(0);\nrecyclerView.removeView(child); // bypasses detach protocol -> throw\n// after: let the layout/recycler handle it, or the LM\nrecyclerView.getLayoutManager().removeAndRecycleViewAt(0, recycler);","handlingStrategy":"validation","validationCode":"// Do not validate around this; instead avoid the API entirely.\n// Ensure children are only removed via the LayoutManager/Recycler:\nif (layoutManager != null) {\n  layoutManager.removeAndRecycleViewAt(index, recycler);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never call ViewGroup.removeView/removeDetachedView on RecyclerView children directly.","Use the LayoutManager's removeAndRecycleViewAt for any child removal.","Keep third-party animation libraries away from RecyclerView's child list."],"tags":["recyclerview","layoutmanager","view-hierarchy","internal-api"],"backgroundTag":null,"analyzedSha":"45ab8f4308496e1f01026a97fcdb0d58a5274474","analyzedAt":"2026-08-14T05:19:30.815Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}