DrKLO/Telegram · error · IllegalArgumentException
View {child} is not a direct child of {this}
Error message
View {child} is not a direct child of {this} What it means
RecyclerView.getChildViewHolder(@NonNull View child) throws IllegalArgumentException when the supplied view's parent is non-null and is not the RecyclerView itself. The method only resolves a ViewHolder for a DIRECT child view; passing a descendant (e.g. a button nested inside an item's root view) or a view belonging to a different parent violates the precondition. Call getChildViewHolderInt for internal resolution; this public API enforces direct-childhood to avoid returning a ViewHolder for the wrong RecyclerView.
Source
Thrown at TMessagesProj/src/main/java/androidx/recyclerview/widget/RecyclerView.java:4784
* @param preserveFocusAfterLayout Whether RecyclerView should preserve focused Item during a
* layout calculations. Defaults to true.
*
* @see #getPreserveFocusAfterLayout()
*/
public void setPreserveFocusAfterLayout(boolean preserveFocusAfterLayout) {
mPreserveFocusAfterLayout = preserveFocusAfterLayout;
}
/**
* Retrieve the {@link ViewHolder} for the given child view.
*
* @param child Child of this RecyclerView to query for its ViewHolder
* @return The child view's ViewHolder
*/
public ViewHolder getChildViewHolder(@NonNull View child) {
final ViewParent parent = child.getParent();
if (parent != null && parent != this) {
throw new IllegalArgumentException("View " + child + " is not a direct child of "
+ this);
}
return getChildViewHolderInt(child);
}
/**
* Traverses the ancestors of the given view and returns the item view that contains it and
* also a direct child of the RecyclerView. This returned view can be used to get the
* ViewHolder by calling {@link #getChildViewHolder(View)}.
*
* @param view The view that is a descendant of the RecyclerView.
*
* @return The direct child of the RecyclerView which contains the given view or null if the
* provided view is not a descendant of this RecyclerView.
*
* @see #getChildViewHolder(View)
* @see #findContainingViewHolder(View)
*/View on GitHub (pinned to 45ab8f4308)
Solutions
- Pass the direct item root view: in a click listener use View itemView = (View) v.getParent() up to the RecyclerView child, or use vh.itemView; better, capture the ViewHolder in the listener when binding rather than re-querying later.
- Use RecyclerView.getChildAdapterPosition(view) with the item root, or set an OnClickListener on the ViewHolder.itemView during onBindViewHolder.
- Before calling, check view.getParent() == recyclerView to guard against detached/migrated views.
Example fix
// before: passing the clicked inner view
itemView.findViewById(R.id.btn).setOnClickListener(v -> {
ViewHolder vh = (ViewHolder) rv.getChildViewHolder(v); // v is not a direct child -> throw
});
// after: capture the holder at bind time
holder.itemView.setOnClickListener(v -> {
int pos = holder.getAdapterPosition();
... // no lookup needed
}); Defensive patterns
Strategy: validation
Validate before calling
ViewParent p = view.getParent();
if (p == recyclerView) {
RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(view);
} else {
// walk up to the direct child, or restructure to capture the holder at bind time
} Prevention
- Capture the ViewHolder/position in the click listener during onBindViewHolder rather than re-querying later.
- Only pass the item root view (holder.itemView) to getChildViewHolder.
- Check view.getParent() == recyclerView before calling.
When it happens
Trigger: Passing a descendant of an item view (e.g. itemView.findViewById(...)) instead of the item root; passing a view that belongs to a different RecyclerView or was already removed from the hierarchy; calling getChildViewHolder during a transient state where the view is detached.
Common situations: Click handlers that pass the clicked inner view (a TextView/Button) rather than the outer card/item root; migrating from ListView where getChildAt was used loosely; views recycled and rebound between queries.
Related errors
- Called removeDetachedView with a view which is not flagged a
- The view does not have a ViewHolder. You cannot pass arbitra
- should not dispatch add or move for pre layout
- op should be remove or update.{}
- only remove and update ops can be dispatched in first pass
AI-assisted analysis of DrKLO/Telegram@45ab8f4308 (2026-08-14).
Data as JSON: /api/errors/02cf4d0c8b3baba3.
Report an issue: GitHub.