PhilJay/MPAndroidChart · error · IllegalArgumentException

The object to recycle already belongs to poolId {object.curr

Error message

The object to recycle already belongs to poolId {object.currentOwnerId}.  Object cannot belong to two different pool instances simultaneously!

What it means

Thrown by ObjectPool.recycle(T) when the object belongs to a different pool (currentOwnerId != NO_OWNER and != this.poolId). A Poolable can only be owned by one pool at a time; recycling it into another pool would violate that invariant. The offending poolId is interpolated into the message.

Source

Thrown at MPChartLib/src/main/java/com/github/mikephil/charting/utils/ObjectPool.java:137

        T result = (T)objects[this.objectsPointer];
        result.currentOwnerId = Poolable.NO_OWNER;
        this.objectsPointer--;

        return result;
    }

    /**
     * Recycle an instance of Poolable that this pool is capable of generating.
     * The T instance passed must not already exist inside this or any other ObjectPool instance.
     *
     * @param object An object of type T to recycle
     */
    public synchronized void recycle(T object){
        if(object.currentOwnerId != Poolable.NO_OWNER){
            if(object.currentOwnerId == this.poolId){
                throw new IllegalArgumentException("The object passed is already stored in this pool!");
            }else {
                throw new IllegalArgumentException("The object to recycle already belongs to poolId " + object.currentOwnerId + ".  Object cannot belong to two different pool instances simultaneously!");
            }
        }

        this.objectsPointer++;
        if(this.objectsPointer >= objects.length){
            this.resizePool();
        }

        object.currentOwnerId = this.poolId;
        objects[this.objectsPointer] = object;

    }

    /**
     * Recycle a List of Poolables that this pool is capable of generating.
     * The T instances passed must not already exist inside this or any other ObjectPool instance.
     *
     * @param objects A list of objects of type T to recycle

View on GitHub (pinned to 9c7275a059)

Solutions

  1. Recycle each object into the exact pool that produced it (track owner via pool.getPoolId()).
  2. Maintain a single pool per object type instead of multiple pools.
  3. Before cross-pool handoff, ensure the object is NO_OWNER (it already is once acquired); do not recycle into a foreign pool.
  4. Tag acquired objects with their source pool id and assert on recycle.

Example fix

// before
Poolable o = poolA.get();
poolB.recycle(o); // throws: belongs to poolA

// after
Poolable o = poolA.get();
poolA.recycle(o); // return to the owner pool
Defensive patterns

Strategy: validation

Validate before calling

if (object.currentOwnerId == Poolable.NO_OWNER || object.currentOwnerId == pool.getPoolId()) {
    pool.recycle(object);
} else {
    Log.w(TAG, "Object belongs to pool " + object.currentOwnerId);
}

Type guard

boolean belongsToPool(Poolable o, ObjectPool pool) {
    return o.currentOwnerId == pool.getPoolId();
}

Prevention

When it happens

Trigger: Acquiring an object from poolA and recycling it into poolB. Sharing Poolable subtypes across two pool instances. Reassigning an object to a newly created pool without releasing it from the old one.

Common situations: Multiple pools for the same type (e.g. one per chart); refactoring that introduced a second pool but reused old objects; cross-thread object handoff where each thread has its own pool.

Related errors


AI-assisted analysis of PhilJay/MPAndroidChart@9c7275a059 (2026-08-14). Data as JSON: /api/errors/b72fc57f06a48b92. Report an issue: GitHub.