{"record":{"id":"150feb662663d84c","repo":"DrKLO/Telegram","slug":"called-attach-on-a-child-which-is-not-detached-v","errorCode":null,"errorMessage":"Called attach on a child which is not detached: {vh}","messagePattern":"Called attach on a child which is not detached: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"critical","filePath":"TMessagesProj/src/main/java/androidx/recyclerview/widget/RecyclerView.java","lineNumber":969,"sourceCode":"                    // 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                RecyclerView.this.removeAllViews();\n            }\n\n            @Override\n            public ViewHolder getChildViewHolder(View view) {\n                return getChildViewHolderInt(view);\n            }\n\n            @Override\n            public void attachViewToParent(View child, int index,\n                    ViewGroup.LayoutParams layoutParams) {\n                final ViewHolder vh = getChildViewHolderInt(child);\n                if (vh != null) {\n                    if (!vh.isTmpDetached() && !vh.shouldIgnore()) {\n                        throw new IllegalArgumentException(\"Called attach on a child which is not\"\n                                + \" detached: \" + vh + exceptionLabel());\n                    }\n                    vh.clearTmpDetachFlag();\n                }\n                RecyclerView.this.attachViewToParent(child, index, layoutParams);\n            }\n\n            @Override\n            public void detachViewFromParent(int offset) {\n                final View view = getChildAt(offset);\n                if (view != null) {\n                    final ViewHolder vh = getChildViewHolderInt(view);\n                    if (vh != null) {\n                        if (vh.isTmpDetached() && !vh.shouldIgnore()) {\n                            throw new IllegalArgumentException(\"called detach on an already\"\n                                    + \" detached child \" + vh + exceptionLabel());\n                        }\n                        vh.addFlags(ViewHolder.FLAG_TMP_DETACHED);","sourceCodeStart":951,"sourceCodeEnd":987,"githubUrl":"https://github.com/DrKLO/Telegram/blob/45ab8f4308496e1f01026a97fcdb0d58a5274474/TMessagesProj/src/main/java/androidx/recyclerview/widget/RecyclerView.java#L951-L987","documentation":"RecyclerView's internal LayoutManager proxy implements attachViewToParent. Before attaching a child it checks the child's ViewHolder: if the holder is NOT marked tmp-detached and does not carry the shouldIgnore flag, it throws 'Called attach on a child which is not detached'. Attaching a view that the ViewGroup still considers attached would corrupt the view tree.","triggerScenarios":"A custom LayoutManager calls layoutManager.attachViewToParent / addView on a child that was never detached via the matching detach path. A mismatched attach/detach sequence in onLayoutChildren (e.g. attach called twice, or attach without a prior detachView).","commonSituations":"Hand-rolled LayoutManager that manages its own scrap recycling and forgets to detach before re-attaching. Off-by-one in recycler/scrap bookkeeping where a still-attached view is reattached. Recycler reuse race during predictive animations.","solutions":["Ensure every attachViewToParent call is preceded by a matching detachViewFromParent (or removeView) for the same child.","Use the Recycler API (recycler.getViewForPosition) instead of manual attach when possible.","In onLayoutChildren, follow detach-all -> fill -> reattach pattern strictly; never attach a view you did not detach."],"exampleFix":"// before (custom LM)\ndetachView(child);            // forgot for some path\nattachViewToParent(child, 0, lp);\n\n// after\n// only attach views you previously detached in this layout pass\nif (isDetached(child)) {\n    attachViewToParent(child, 0, lp);\n}","handlingStrategy":"validation","validationCode":"// In a custom LayoutManager, only attach children you have detached in this pass\nView child = getChildAt(i);\nRecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(child);\nif (vh != null && (vh.isTmpDetached() || vh.shouldIgnore())) {\n    attachViewToParent(child, index, lp);\n}","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Follow strict detach-then-attach ordering in onLayoutChildren.","Prefer Recycler.getViewForPosition over manual attach when possible.","Add assertions in debug builds that track attach/detach pairs."],"tags":["recyclerview","layoutmanager","view-tree","lifecycle"],"backgroundTag":null,"analyzedSha":"45ab8f4308496e1f01026a97fcdb0d58a5274474","analyzedAt":"2026-08-14T05:19:30.815Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}