PGVector / Postgres connection is not automatically closed, and remains idle #63

Open
opened 2026-02-16 05:16:23 -05:00 by yindo · 6 comments
Owner

Originally created by @Lengo46 on GitHub (Jan 2, 2025).

Checked other resources

  • I added a very descriptive title to this issue.
  • I searched the LangChain documentation with the integrated search.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangChain rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).

Example Code

from datetime import datetime
from langchain_postgres import PGVector
from langchain_openai import OpenAIEmbeddings
from dotenv import load_dotenv

load_dotenv()

connection = os.getenv('POSTGRES_CONNECTION_STRING')  
embeddings = OpenAIEmbeddings(model="text-embedding-ada-002")

async def vectorStore(pg_table_name: str, remove = False):
    return PGVector(
        embeddings=embeddings,
        collection_name=pg_table_name,
        connection=connection,
        use_jsonb=True,
        pre_delete_collection=remove,
    )

### Error Message and Stack Trace (if applicable)

`psql: FATAL: remaining connection slots are reserved for non-replication superuser connections`

If I query the database, it's clearly that all connections remain idle and open.



### Description

This is a bug that was fixed in the past, see https://github.com/langchain-ai/langchain/issues/9696.  The PG Vector file has move to an import to  lanchain_postgres somewhere in the last year, which doesn't contain the fix for this issue.



### System Info

System Information
------------------
> OS:  Darwin
> OS Version:  Darwin Kernel Version 24.1.0: Thu Oct 10 21:03:15 PDT 2024; root:xnu-11215.41.3~2/RELEASE_ARM64_T6000
> Python Version:  3.11.1 (main, Jan  4 2023, 15:58:50) [Clang 14.0.0 (clang-1400.0.29.202)]

Package Information
-------------------
> langchain_core: 0.3.21
> langchain: 0.3.9
> langchain_community: 0.3.8
> langsmith: 0.1.135
> langchain_ollama: 0.2.0
> langchain_openai: 0.2.2
> langchain_postgres: 0.0.12
> langchain_text_splitters: 0.3.0

Optional packages not installed
-------------------------------
> langserve

Other Dependencies
------------------
> aiohttp: 3.10.10
> async-timeout: 4.0.3
> dataclasses-json: 0.6.7
> httpx: 0.27.2
> httpx-sse: 0.4.0
> jsonpatch: 1.33
> numpy: 1.26.4
> ollama: 0.3.3
> openai: 1.51.2
> orjson: 3.10.7
> packaging: 24.1
> pgvector: 0.2.5
> psycopg: 3.2.3
> psycopg-pool: 3.2.3
> pydantic: 2.10.4
> pydantic-settings: 2.5.2
> PyYAML: 6.0.2
> requests: 2.32.3
> requests-toolbelt: 1.0.0
> SQLAlchemy: 2.0.35
> sqlalchemy: 2.0.35
> tenacity: 8.5.0
> tiktoken: 0.8.0
> typing-extensions: 4.12.2
Originally created by @Lengo46 on GitHub (Jan 2, 2025). ### Checked other resources - [X] I added a very descriptive title to this issue. - [X] I searched the LangChain documentation with the integrated search. - [X] I used the GitHub search to find a similar question and didn't find it. - [X] I am sure that this is a bug in LangChain rather than my code. - [X] The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package). ### Example Code ```import os from datetime import datetime from langchain_postgres import PGVector from langchain_openai import OpenAIEmbeddings from dotenv import load_dotenv load_dotenv() connection = os.getenv('POSTGRES_CONNECTION_STRING') embeddings = OpenAIEmbeddings(model="text-embedding-ada-002") async def vectorStore(pg_table_name: str, remove = False): return PGVector( embeddings=embeddings, collection_name=pg_table_name, connection=connection, use_jsonb=True, pre_delete_collection=remove, ) ### Error Message and Stack Trace (if applicable) `psql: FATAL: remaining connection slots are reserved for non-replication superuser connections` If I query the database, it's clearly that all connections remain idle and open. ### Description This is a bug that was fixed in the past, see https://github.com/langchain-ai/langchain/issues/9696. The PG Vector file has move to an import to lanchain_postgres somewhere in the last year, which doesn't contain the fix for this issue. ### System Info System Information ------------------ > OS: Darwin > OS Version: Darwin Kernel Version 24.1.0: Thu Oct 10 21:03:15 PDT 2024; root:xnu-11215.41.3~2/RELEASE_ARM64_T6000 > Python Version: 3.11.1 (main, Jan 4 2023, 15:58:50) [Clang 14.0.0 (clang-1400.0.29.202)] Package Information ------------------- > langchain_core: 0.3.21 > langchain: 0.3.9 > langchain_community: 0.3.8 > langsmith: 0.1.135 > langchain_ollama: 0.2.0 > langchain_openai: 0.2.2 > langchain_postgres: 0.0.12 > langchain_text_splitters: 0.3.0 Optional packages not installed ------------------------------- > langserve Other Dependencies ------------------ > aiohttp: 3.10.10 > async-timeout: 4.0.3 > dataclasses-json: 0.6.7 > httpx: 0.27.2 > httpx-sse: 0.4.0 > jsonpatch: 1.33 > numpy: 1.26.4 > ollama: 0.3.3 > openai: 1.51.2 > orjson: 3.10.7 > packaging: 24.1 > pgvector: 0.2.5 > psycopg: 3.2.3 > psycopg-pool: 3.2.3 > pydantic: 2.10.4 > pydantic-settings: 2.5.2 > PyYAML: 6.0.2 > requests: 2.32.3 > requests-toolbelt: 1.0.0 > SQLAlchemy: 2.0.35 > sqlalchemy: 2.0.35 > tenacity: 8.5.0 > tiktoken: 0.8.0 > typing-extensions: 4.12.2
Author
Owner

@Lengo46 commented on GitHub (Jan 10, 2025):

Any help on this?

@Lengo46 commented on GitHub (Jan 10, 2025): Any help on this?
Author
Owner

@m-ibraheem-tkxel commented on GitHub (Feb 6, 2025):

I am working on v0.0.9

We had implemented a custom close function as a temporary measure and ended up using

def close(self):
if self.vectorstore is not None:
if hasattr(self.vectorstore, "__async_engine"):
self.vectorstore.__async_engine.close()
if hasattr(self.vectorstore, "__engine"):
self.vectorstore.__engine.close()

where self.vectorstore is an instance of PGVector.

Please share if there is a better way to do this in the newer versions.

@m-ibraheem-tkxel commented on GitHub (Feb 6, 2025): I am working on v0.0.9 We had implemented a custom close function as a temporary measure and ended up using def close(self): if self.vectorstore is not None: if hasattr(self.vectorstore, "__async_engine"): self.vectorstore.__async_engine.close() if hasattr(self.vectorstore, "__engine"): self.vectorstore.__engine.close() where self.vectorstore is an instance of PGVector. Please share if there is a better way to do this in the newer versions.
Author
Owner

@chunyeah commented on GitHub (May 6, 2025):

Any update with issue plz

@chunyeah commented on GitHub (May 6, 2025): Any update with issue plz
Author
Owner

@bhavan-kaya commented on GitHub (Jul 20, 2025):

Facing the same issue on our end, is there a way to expose the close method to be used outside so that the connections could be manually stoped

@bhavan-kaya commented on GitHub (Jul 20, 2025): Facing the same issue on our end, is there a way to expose the close method to be used outside so that the connections could be manually stoped
Author
Owner

@volkanncicek commented on GitHub (Jul 21, 2025):

Hi @bhavan-kaya and others following this issue,

I've analyzed this problem and found the root cause of the connection leak. I've implemented a fix in my forked repository, which you can review here:

https://github.com/volkanncicek/langchain-postgres

The core of the issue is a global variable, _classes, used to cache the SQLAlchemy models. My investigation showed that this variable causes the problem because:

  1. Single Global Cache: The models are generated and cached in _classes only once, during the very first PGVector instantiation.
  2. No Isolation: This single cached model is then reused for all subsequent PGVector instances, even if they use different database connections or schemas.
  3. Connection Leak: The model metadata remains tied to the engine of the first connection. When a new instance is created with a different connection, it reuses the old models, which in turn keeps a reference to the old engine. This prevents the old connection pool from being closed, leading to the "idle" connections that never get released.

My solution replaces the problematic global _classes variable with a _class_cache dictionary. This new approach uses the table_schema as a key, ensuring that a unique set of EmbeddingStore and CollectionStore classes is generated for each schema. This isolates the models and their corresponding engines, allowing SQLAlchemy to properly manage and close connection pools when they are no longer in use.

I believe this permanently resolves the connection leak. Hope this helps

@volkanncicek commented on GitHub (Jul 21, 2025): Hi @bhavan-kaya and others following this issue, I've analyzed this problem and found the root cause of the connection leak. I've implemented a fix in my forked repository, which you can review here: **https://github.com/volkanncicek/langchain-postgres** The core of the issue is a global variable, `_classes`, used to cache the SQLAlchemy models. My investigation showed that this variable causes the problem because: 1. **Single Global Cache:** The models are generated and cached in `_classes` only once, during the very first `PGVector` instantiation. 2. **No Isolation:** This single cached model is then reused for **all** subsequent `PGVector` instances, even if they use different database connections or schemas. 3. **Connection Leak:** The model metadata remains tied to the engine of the *first* connection. When a new instance is created with a different connection, it reuses the old models, which in turn keeps a reference to the old engine. This prevents the old connection pool from being closed, leading to the "idle" connections that never get released. My solution replaces the problematic global `_classes` variable with a `_class_cache` dictionary. This new approach uses the `table_schema` as a key, ensuring that a unique set of `EmbeddingStore` and `CollectionStore` classes is generated for each schema. This isolates the models and their corresponding engines, allowing SQLAlchemy to properly manage and close connection pools when they are no longer in use. I believe this permanently resolves the connection leak. Hope this helps
Author
Owner

@cmd-AKASH commented on GitHub (Aug 14, 2025):

Facing the same issue on our end, is there a way to expose the close method to be used outside so that the connections could be manually stoped

We ran into the same issue. I subclassed PGVector and added a public close() method so the DB connection can be explicitly disposed of after use.

class CustomPGVector(PGVector):
    """Custom PGVector class with method to close the DB connection."""

    def close(self):
        """Close the connection to the vector store."""
        if isinstance(self._engine, Engine):
            self._engine.dispose()

Usage:

vector_db = CustomPGVector(...)
# ... use vector_db ...
vector_db.close()  # manually release connection

This only handles the synchronous Engine case.
Works fine for us as a stopgap until the community resolves the issue.

P.S.: If it works, never touch it 😆

@cmd-AKASH commented on GitHub (Aug 14, 2025): > Facing the same issue on our end, is there a way to expose the close method to be used outside so that the connections could be manually stoped We ran into the same issue. I subclassed `PGVector` and added a public close() method so the DB connection can be explicitly disposed of after use. ```python class CustomPGVector(PGVector): """Custom PGVector class with method to close the DB connection.""" def close(self): """Close the connection to the vector store.""" if isinstance(self._engine, Engine): self._engine.dispose() ``` Usage: ```python vector_db = CustomPGVector(...) # ... use vector_db ... vector_db.close() # manually release connection ``` This only handles the synchronous Engine case. Works fine for us as a stopgap until the community resolves the issue. P.S.: If it works, never touch it 😆
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langchain-postgres#63