DrKLO/Telegram · error · IllegalArgumentException
The view does not have a ViewHolder. You cannot pass arbitra
Error message
The view does not have a ViewHolder. You cannot pass arbitrary views to this method, they should be created by the Adapter
What it means
Recycler.bindViewToPosition throws IllegalArgumentException when the supplied view has no associated ViewHolder. bindViewToPosition is a LayoutManager-facing API that re-binds an existing adapter-created view to a new position; it looks up the view's ViewHolder via getChildViewHolderInt, and a null result means the view was never created by the Adapter (it is an arbitrary, non-RecyclerView view). Only views that passed through the adapter's onCreateViewHolder/onBindViewHolder lifecycle carry a ViewHolder (stored in LayoutParams.mViewHolder).
Source
Thrown at TMessagesProj/src/main/java/androidx/recyclerview/widget/RecyclerView.java:6058
/**
* Binds the given View to the position. The View can be a View previously retrieved via
* {@link #getViewForPosition(int)} or created by
* {@link Adapter#onCreateViewHolder(ViewGroup, int)}.
* <p>
* Generally, a LayoutManager should acquire its views via {@link #getViewForPosition(int)}
* and let the RecyclerView handle caching. This is a helper method for LayoutManager who
* wants to handle its own recycling logic.
* <p>
* Note that, {@link #getViewForPosition(int)} already binds the View to the position so
* you don't need to call this method unless you want to bind this View to another position.
*
* @param view The view to update.
* @param position The position of the item to bind to this View.
*/
public void bindViewToPosition(@NonNull View view, int position) {
ViewHolder holder = getChildViewHolderInt(view);
if (holder == null) {
throw new IllegalArgumentException("The view does not have a ViewHolder. You cannot"
+ " pass arbitrary views to this method, they should be created by the "
+ "Adapter" + exceptionLabel());
}
final int offsetPosition = mAdapterHelper.findPositionOffset(position);
if (offsetPosition < 0 || offsetPosition >= mAdapter.getItemCount()) {
throw new IndexOutOfBoundsException("Inconsistency detected. Invalid item "
+ "position " + position + "(offset:" + offsetPosition + ")."
+ "state:" + mState.getItemCount() + exceptionLabel());
}
tryBindViewHolderByDeadline(holder, offsetPosition, position, FOREVER_NS);
final ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
final LayoutParams rvLayoutParams;
if (lp == null) {
rvLayoutParams = (LayoutParams) generateDefaultLayoutParams();
holder.itemView.setLayoutParams(rvLayoutParams);
} else if (!checkLayoutParams(lp)) {
rvLayoutParams = (LayoutParams) generateLayoutParams(lp);View on GitHub (pinned to 45ab8f4308)
Solutions
- Only pass views obtained from Recycler.getViewForPosition(int) (or getRecycledViewPool) into bindViewToPosition — these carry a ViewHolder.
- In a custom LayoutManager, always obtain child views via the provided Recycler parameter, never via LayoutInflater or new View.
- If you must introduce a non-adapter view, do so outside the Recycler pipeline (e.g. as a separate decorated header managed by the LayoutManager, not bound through the adapter).
Example fix
// before (custom LayoutManager) View v = LayoutInflater.from(ctx).inflate(R.layout.item, rv, false); recycler.bindViewToPosition(v, pos); // v has no ViewHolder -> throw // after View v = recycler.getViewForPosition(pos); // created/bound by adapter, has VH addView(v); measureChildWithMargins(v, 0, 0);
Defensive patterns
Strategy: type-guard
Validate before calling
// Only bind views obtained from the Recycler View v = recycler.getViewForPosition(pos); // guaranteed to have a ViewHolder recycler.bindViewToPosition(v, pos);
Type guard
static boolean isAdapterCreatedView(View v, RecyclerView rv) {
ViewGroup.LayoutParams lp = v.getLayoutParams();
return lp instanceof RecyclerView.LayoutParams
&& ((RecyclerView.LayoutParams) lp).getViewHolder() != null;
} Prevention
- In a custom LayoutManager, obtain child views only via recycler.getViewForPosition.
- Never inflate or construct views to pass into the Recycler bind API.
- Treat the Recycler API as internal: prefer adapter-driven view creation.
When it happens
Trigger: A custom LayoutManager passing an externally created View (not from Recycler.getViewForPosition) into bindViewToPosition; manually inflating a view and handing it to the Recycler; a view whose ViewHolder was stripped during recycling due to a bug.
Common situations: Custom LayoutManager misuse; experimenting with Recycler internals; a third-party library that injects views into the Recycler bypassing the adapter; recycled view whose LayoutParams were replaced.
Related errors
- Called removeDetachedView with a view which is not flagged a
- view is not a child, cannot hide {}
- Layout positions must be non-negative
- Pixel distance must be non-negative
- invalid orientation:{}
AI-assisted analysis of DrKLO/Telegram@45ab8f4308 (2026-08-14).
Data as JSON: /api/errors/2bf3706b9cf984e2.
Report an issue: GitHub.