PGVector destructor closes externally supplied connection_pool
Summary
In mem0ai 2.0.20, PGVector accepts an externally supplied connection_pool, but del closes that pool without tracking ownership. Disposing one Memory/vector-store instance can therefore close a shared, application-owned pool used by other instances.
Source
mem0/vector_stores/pgvector.py:
- Lines 191–193: supplied connection_pool is assigned directly.
- Lines 202–214: pool construction is skipped when one was supplied.
- Lines 545–556: del unconditionally calls connection_pool.close() (psycopg 3) or closeall() (psycopg 2).
Minimal reproducer (no database needed)
import gc
from mem0.vector_stores.pgvector import PGVector
class ExternalPool:
def __init__(self):
self.closed = False
def close(self):
self.closed = True
def closeall(self):
self.closed = True
pool = ExternalPool()
store = PGVector(
dbname="postgres", collection_name="example",
embedding_model_dims=8, user=None, password=None,
host=None, port=None, diskann=False, hnsw=False,
connection_pool=pool,
)
assert store.connection_pool is pool
del store
gc.collect()
assert not pool.closed # Fails: destruction closed an externally owned pool.
Expected behavior
Record whether PGVector constructed its own pool, and only dispose owned pools. An application that supplies a shared pool should remain responsible for closing it.
Impact
This prevents safely injecting one process-owned psycopg pool into short-lived Memory instances. A borrowed-pool wrapper that delegates operations and makes close/closeall no-ops is an application-side workaround, but ownership handling in PGVector would avoid requiring it.
Environment inspected: mem0ai 2.0.20, psycopg 3.3.4, psycopg-pool 3.3.1.
Source: mem0ai/mem0