airbnb/epoxy · error · UnsupportedOperationException

UnboundedViewPool does not support setting a maximum number…

Error message

UnboundedViewPool does not support setting a maximum number of recycled views

What it means

UnboundedViewPool is a RecyclerView.ViewHolder pool with no per-viewType size cap, implemented by overriding Epoxy's ViewPool. setMaxRecycledViews is intentionally unsupported because a cap contradicts the pool's unbounded design, so calling it always throws UnsupportedOperationException.

Solutions

  1. Remove the setMaxRecycledViews call when using UnboundedViewPool — it is unbounded by design.
  2. Use a bounded pool (e.g. standard RecyclerView.RecycledViewPool or Epoxy's default ViewPool) if you need per-type caps.
  3. Branch on pool type before configuring: only call setMaxRecycledViews when the pool supports it.
  4. Control memory instead by limiting how many holders RecyclerView can create (layout manager hints) or using a different pool.

Example fix

// before
val pool = UnboundedViewPool()
pool.setMaxRecycledViews(0, 5) // throws

// after
val pool: RecyclerView.RecycledViewPool =
  if (needCaps) RecyclerView.RecycledViewPool().apply { setMaxRecycledViews(0, 5) }
  else UnboundedViewPool()
Defensive patterns

Strategy: type-guard

Type guard

fun RecyclerView.RecycledViewPool.setMaxIfSupported(viewType: Int, max: Int) {
  if (this is UnboundedViewPool) return
  setMaxRecycledViews(viewType, max)
}

Prevention

When it happens

Trigger: Calling setMaxRecycledViews(viewType, max) on an UnboundedViewPool instance, directly or via code that configures a generic ViewPool/RecycledViewPool without knowing the concrete type.

Common situations: Shared pool-configuration utility code that sets max sizes for every pool including unbounded ones; swapping a bounded RecycledViewPool for UnboundedViewPool to fix memory churn while keeping the old sizing calls; copy-pasted RecyclerView setup.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of airbnb/epoxy@e45bd3a61f (2026-09-13). Data as JSON: /api/errors/3ebdb6119a1404dd. Report an issue: GitHub.

Appendix: source

Thrown at epoxy-adapter/src/main/java/com/airbnb/epoxy/UnboundedViewPool.kt:24

import java.util.LinkedList
import java.util.Queue

/**
 * Like its parent, UnboundedViewPool lets you share Views between multiple RecyclerViews. However
 * there is no maximum number of recycled views that it will store. This usually ends up being
 * optimal, barring any hard memory constraints, as RecyclerViews do not recycle more Views than
 * they need.
 */
internal class UnboundedViewPool : RecycledViewPool() {

    private val scrapHeaps = SparseArray<Queue<ViewHolder>>()

    override fun clear() {
        scrapHeaps.clear()
    }

    override fun setMaxRecycledViews(viewType: Int, max: Int) {
        throw UnsupportedOperationException(
            "UnboundedViewPool does not support setting a maximum number of recycled views"
        )
    }

    override fun getRecycledView(viewType: Int): ViewHolder? {
        val scrapHeap = scrapHeaps.get(viewType)
        return scrapHeap?.poll()
    }

    override fun putRecycledView(viewHolder: ViewHolder) {
        getScrapHeapForType(viewHolder.itemViewType).add(viewHolder)
    }

    override fun getRecycledViewCount(viewType: Int): Int {
        return scrapHeaps.get(viewType)?.size ?: 0
    }

    private fun getScrapHeapForType(viewType: Int): Queue<ViewHolder> {

View on GitHub (pinned to e45bd3a61f)