AsyncPostgresSaver uses hardcoded pipeline=True even if no pipeline is available #310

Closed
opened 2026-02-20 17:36:02 -05:00 by yindo · 4 comments
Owner

Originally created by @epistoteles on GitHub (Nov 13, 2024).

Checked other resources

  • I added a very descriptive title to this issue.
  • I searched the LangGraph/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 LangGraph/LangChain rather than my code.
  • I am sure this is better as an issue rather than a GitHub discussion, since this is a LangGraph bug and not a design question.

Example Code

any usage of the AsyncPostgresSaver where pipelines are not supported

Error Message and Stack Trace (if applicable)

2024-11-13T13:41:45.856830355Z     await self.asgi_app(scope, receive, send)
2024-11-13T13:41:45.856836855Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/opentelemetry/instrumentation/asgi/__init__.py", line 735, in __call__
2024-11-13T13:41:45.856842156Z     await self.app(scope, otel_receive, otel_send)
2024-11-13T13:41:45.856847056Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/quart/app.py", line 1693, in asgi_app
2024-11-13T13:41:45.856851957Z     await asgi_handler(receive, send)
2024-11-13T13:41:45.856865358Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/quart/asgi.py", line 52, in __call__
2024-11-13T13:41:45.856870358Z     raise_task_exceptions(done)
2024-11-13T13:41:45.856875059Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/quart/utils.py", line 180, in raise_task_exceptions
2024-11-13T13:41:45.856880059Z     raise task.exception()
2024-11-13T13:41:45.856884659Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/quart/asgi.py", line 107, in handle_request
2024-11-13T13:41:45.856889560Z     await asyncio.wait_for(self._send_response(send, response), timeout=timeout)
2024-11-13T13:41:45.856894360Z   File "/opt/python/3.11.8/lib/python3.11/asyncio/tasks.py", line 489, in wait_for
2024-11-13T13:41:45.856899061Z     return fut.result()
2024-11-13T13:41:45.856903661Z            ^^^^^^^^^^^^
2024-11-13T13:41:45.856908361Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/quart/asgi.py", line 134, in _send_response
2024-11-13T13:41:45.856913262Z     async for data in response_body:
2024-11-13T13:41:45.856918162Z   File "/tmp/8dd03de0847602f/decorators.py", line 73, in wrapper
2024-11-13T13:41:45.856922863Z     async for chunk in func(*args, **kwargs):
2024-11-13T13:41:45.856927463Z   File "/tmp/8dd03de0847602f/approaches/langgraph_approach.py", line 176, in run
2024-11-13T13:41:45.856934964Z     async for msg, _ in self.graph.astream(inputs, config, stream_mode="messages"):
2024-11-13T13:41:45.856940064Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/langgraph/pregel/__init__.py", line 1506, in astream
2024-11-13T13:41:45.856944864Z     async with AsyncPregelLoop(
2024-11-13T13:41:45.856949465Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/langgraph/pregel/loop.py", line 877, in __aexit__
2024-11-13T13:41:45.856954265Z     return await asyncio.shield(
2024-11-13T13:41:45.856958866Z            ^^^^^^^^^^^^^^^^^^^^^
2024-11-13T13:41:45.856963466Z   File "/opt/python/3.11.8/lib/python3.11/contextlib.py", line 745, in __aexit__
2024-11-13T13:41:45.856968166Z     raise exc_details[1]
2024-11-13T13:41:45.856972667Z   File "/opt/python/3.11.8/lib/python3.11/contextlib.py", line 728, in __aexit__
2024-11-13T13:41:45.856977467Z     cb_suppress = await cb(*exc_details)
2024-11-13T13:41:45.856981967Z                   ^^^^^^^^^^^^^^^^^^^^^^
2024-11-13T13:41:45.856991468Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/langgraph/pregel/executor.py", line 191, in __aexit__
2024-11-13T13:41:45.856996469Z     raise exc
2024-11-13T13:41:45.857001069Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/langgraph/pregel/loop.py", line 797, in _checkpointer_put_after_previous
2024-11-13T13:41:45.857005969Z     await prev
2024-11-13T13:41:45.857010470Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/langgraph/pregel/loop.py", line 799, in _checkpointer_put_after_previous
2024-11-13T13:41:45.857015370Z     await cast(BaseCheckpointSaver, self.checkpointer).aput(
2024-11-13T13:41:45.857019971Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/langgraph/checkpoint/postgres/aio.py", line 267, in aput
2024-11-13T13:41:45.857024671Z     async with self._cursor(pipeline=True) as cur:
2024-11-13T13:41:45.857029171Z   File "/opt/python/3.11.8/lib/python3.11/contextlib.py", line 210, in __aenter__
2024-11-13T13:41:45.857034172Z     return await anext(self.gen)
2024-11-13T13:41:45.857038672Z            ^^^^^^^^^^^^^^^^^^^^^
2024-11-13T13:41:45.857043073Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/langgraph/checkpoint/postgres/aio.py", line 340, in _cursor
2024-11-13T13:41:45.857047873Z     async with self.lock, conn.pipeline(), conn.cursor(
2024-11-13T13:41:45.857052373Z   File "/opt/python/3.11.8/lib/python3.11/contextlib.py", line 210, in __aenter__
2024-11-13T13:41:45.857057074Z     return await anext(self.gen)
2024-11-13T13:41:45.857061474Z            ^^^^^^^^^^^^^^^^^^^^^
2024-11-13T13:41:45.857065974Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/psycopg/connection_async.py", line 398, in pipeline
2024-11-13T13:41:45.857070775Z     async with pipeline:
2024-11-13T13:41:45.857075275Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/psycopg/_pipeline.py", line 249, in __aenter__
2024-11-13T13:41:45.857080376Z     await self._conn.wait(self._enter_gen())
2024-11-13T13:41:45.857084976Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/psycopg/connection_async.py", line 414, in wait
2024-11-13T13:41:45.857089676Z     return await waiting.wait_async(gen, self.pgconn.socket, interval=interval)
2024-11-13T13:41:45.857094377Z            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-11-13T13:41:45.857098877Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/psycopg/waiting.py", line 132, in wait_async
2024-11-13T13:41:45.857103578Z     s = next(gen)
2024-11-13T13:41:45.857107978Z         ^^^^^^^^^
2024-11-13T13:41:45.857112378Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/psycopg/_pipeline.py", line 69, in _enter_gen
2024-11-13T13:41:45.857117079Z     capabilities.has_pipeline(check=True)
2024-11-13T13:41:45.857121579Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/psycopg/_capabilities.py", line 41, in has_pipeline
2024-11-13T13:41:45.857130180Z     return self._has_feature("Connection.pipeline()", 140000, check=check)
2024-11-13T13:41:45.857134980Z            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-11-13T13:41:45.857139481Z   File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/psycopg/_capabilities.py", line 92, in _has_feature
2024-11-13T13:41:45.857144181Z     raise NotSupportedError(msg)
2024-11-13T13:41:45.857148681Z psycopg.NotSupportedError: the feature 'Connection.pipeline()' is not available: the client libpq version (imported from system libraries) is 13.14; the feature requires libpq version 14.0 or newer

Description

I'm using the AsyncPostgresSaver on a server that has libpq 13.4 available. Only versions of libpq >=14.0 support pipelines.

Usually this should be respected by the Saver - for example, the from_conn_str() method has a boolean pipeline that can be set. The same applies for the regular constructor, which can be called without a pipeline. I create my AsyncPostgresSaver without a pipeline.

However, there are two calls to _cursor in the code of the AsyncPostgresSaver where the existence of a pipe is not checked, and _cursor is called hardcoded as _cursor(pipeline=True), namely aput_writes() and aput().

This will throw an error for all users that use Postgres without pipeline support.

It's not fully clear to me why it would ever be necessary to use pipline=True if no pipe exists in the class instance.

System Info

langgraph==0.2.45
langgraph-checkpoint-postgres==2.0.2

Originally created by @epistoteles on GitHub (Nov 13, 2024). ### Checked other resources - [X] I added a very descriptive title to this issue. - [X] I searched the [LangGraph](https://langchain-ai.github.io/langgraph/)/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 LangGraph/LangChain rather than my code. - [X] I am sure this is better as an issue [rather than a GitHub discussion](https://github.com/langchain-ai/langgraph/discussions/new/choose), since this is a LangGraph bug and not a design question. ### Example Code ```python any usage of the AsyncPostgresSaver where pipelines are not supported ``` ### Error Message and Stack Trace (if applicable) ```shell 2024-11-13T13:41:45.856830355Z await self.asgi_app(scope, receive, send) 2024-11-13T13:41:45.856836855Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/opentelemetry/instrumentation/asgi/__init__.py", line 735, in __call__ 2024-11-13T13:41:45.856842156Z await self.app(scope, otel_receive, otel_send) 2024-11-13T13:41:45.856847056Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/quart/app.py", line 1693, in asgi_app 2024-11-13T13:41:45.856851957Z await asgi_handler(receive, send) 2024-11-13T13:41:45.856865358Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/quart/asgi.py", line 52, in __call__ 2024-11-13T13:41:45.856870358Z raise_task_exceptions(done) 2024-11-13T13:41:45.856875059Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/quart/utils.py", line 180, in raise_task_exceptions 2024-11-13T13:41:45.856880059Z raise task.exception() 2024-11-13T13:41:45.856884659Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/quart/asgi.py", line 107, in handle_request 2024-11-13T13:41:45.856889560Z await asyncio.wait_for(self._send_response(send, response), timeout=timeout) 2024-11-13T13:41:45.856894360Z File "/opt/python/3.11.8/lib/python3.11/asyncio/tasks.py", line 489, in wait_for 2024-11-13T13:41:45.856899061Z return fut.result() 2024-11-13T13:41:45.856903661Z ^^^^^^^^^^^^ 2024-11-13T13:41:45.856908361Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/quart/asgi.py", line 134, in _send_response 2024-11-13T13:41:45.856913262Z async for data in response_body: 2024-11-13T13:41:45.856918162Z File "/tmp/8dd03de0847602f/decorators.py", line 73, in wrapper 2024-11-13T13:41:45.856922863Z async for chunk in func(*args, **kwargs): 2024-11-13T13:41:45.856927463Z File "/tmp/8dd03de0847602f/approaches/langgraph_approach.py", line 176, in run 2024-11-13T13:41:45.856934964Z async for msg, _ in self.graph.astream(inputs, config, stream_mode="messages"): 2024-11-13T13:41:45.856940064Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/langgraph/pregel/__init__.py", line 1506, in astream 2024-11-13T13:41:45.856944864Z async with AsyncPregelLoop( 2024-11-13T13:41:45.856949465Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/langgraph/pregel/loop.py", line 877, in __aexit__ 2024-11-13T13:41:45.856954265Z return await asyncio.shield( 2024-11-13T13:41:45.856958866Z ^^^^^^^^^^^^^^^^^^^^^ 2024-11-13T13:41:45.856963466Z File "/opt/python/3.11.8/lib/python3.11/contextlib.py", line 745, in __aexit__ 2024-11-13T13:41:45.856968166Z raise exc_details[1] 2024-11-13T13:41:45.856972667Z File "/opt/python/3.11.8/lib/python3.11/contextlib.py", line 728, in __aexit__ 2024-11-13T13:41:45.856977467Z cb_suppress = await cb(*exc_details) 2024-11-13T13:41:45.856981967Z ^^^^^^^^^^^^^^^^^^^^^^ 2024-11-13T13:41:45.856991468Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/langgraph/pregel/executor.py", line 191, in __aexit__ 2024-11-13T13:41:45.856996469Z raise exc 2024-11-13T13:41:45.857001069Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/langgraph/pregel/loop.py", line 797, in _checkpointer_put_after_previous 2024-11-13T13:41:45.857005969Z await prev 2024-11-13T13:41:45.857010470Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/langgraph/pregel/loop.py", line 799, in _checkpointer_put_after_previous 2024-11-13T13:41:45.857015370Z await cast(BaseCheckpointSaver, self.checkpointer).aput( 2024-11-13T13:41:45.857019971Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/langgraph/checkpoint/postgres/aio.py", line 267, in aput 2024-11-13T13:41:45.857024671Z async with self._cursor(pipeline=True) as cur: 2024-11-13T13:41:45.857029171Z File "/opt/python/3.11.8/lib/python3.11/contextlib.py", line 210, in __aenter__ 2024-11-13T13:41:45.857034172Z return await anext(self.gen) 2024-11-13T13:41:45.857038672Z ^^^^^^^^^^^^^^^^^^^^^ 2024-11-13T13:41:45.857043073Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/langgraph/checkpoint/postgres/aio.py", line 340, in _cursor 2024-11-13T13:41:45.857047873Z async with self.lock, conn.pipeline(), conn.cursor( 2024-11-13T13:41:45.857052373Z File "/opt/python/3.11.8/lib/python3.11/contextlib.py", line 210, in __aenter__ 2024-11-13T13:41:45.857057074Z return await anext(self.gen) 2024-11-13T13:41:45.857061474Z ^^^^^^^^^^^^^^^^^^^^^ 2024-11-13T13:41:45.857065974Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/psycopg/connection_async.py", line 398, in pipeline 2024-11-13T13:41:45.857070775Z async with pipeline: 2024-11-13T13:41:45.857075275Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/psycopg/_pipeline.py", line 249, in __aenter__ 2024-11-13T13:41:45.857080376Z await self._conn.wait(self._enter_gen()) 2024-11-13T13:41:45.857084976Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/psycopg/connection_async.py", line 414, in wait 2024-11-13T13:41:45.857089676Z return await waiting.wait_async(gen, self.pgconn.socket, interval=interval) 2024-11-13T13:41:45.857094377Z ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2024-11-13T13:41:45.857098877Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/psycopg/waiting.py", line 132, in wait_async 2024-11-13T13:41:45.857103578Z s = next(gen) 2024-11-13T13:41:45.857107978Z ^^^^^^^^^ 2024-11-13T13:41:45.857112378Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/psycopg/_pipeline.py", line 69, in _enter_gen 2024-11-13T13:41:45.857117079Z capabilities.has_pipeline(check=True) 2024-11-13T13:41:45.857121579Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/psycopg/_capabilities.py", line 41, in has_pipeline 2024-11-13T13:41:45.857130180Z return self._has_feature("Connection.pipeline()", 140000, check=check) 2024-11-13T13:41:45.857134980Z ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2024-11-13T13:41:45.857139481Z File "/tmp/8dd03de0847602f/antenv/lib/python3.11/site-packages/psycopg/_capabilities.py", line 92, in _has_feature 2024-11-13T13:41:45.857144181Z raise NotSupportedError(msg) 2024-11-13T13:41:45.857148681Z psycopg.NotSupportedError: the feature 'Connection.pipeline()' is not available: the client libpq version (imported from system libraries) is 13.14; the feature requires libpq version 14.0 or newer ``` ### Description I'm using the AsyncPostgresSaver on a server that has libpq 13.4 available. Only versions of libpq >=14.0 support pipelines. Usually this should be respected by the Saver - for example, the from_conn_str() method has a boolean pipeline that can be set. The same applies for the regular constructor, which can be called without a pipeline. I create my AsyncPostgresSaver *without* a pipeline. However, there are two calls to _cursor in the code of the AsyncPostgresSaver where the existence of a pipe is not checked, and _cursor is called *hardcoded* as _cursor(pipeline=True), namely **aput_writes()** and **aput()**. This will throw an error for all users that use Postgres without pipeline support. It's not fully clear to me why it would ever be necessary to use pipline=True if no pipe exists in the class instance. ### System Info langgraph==0.2.45 langgraph-checkpoint-postgres==2.0.2
yindo closed this issue 2026-02-20 17:36:04 -05:00
Author
Owner

@lucatrovato commented on GitHub (Nov 18, 2024):

This is a general problem also with the PostgresSaver. @vbarda any idea on when will the fix be released?

@lucatrovato commented on GitHub (Nov 18, 2024): This is a general problem also with the PostgresSaver. @vbarda any idea on when will the fix be released?
Author
Owner

@vbarda commented on GitHub (Nov 18, 2024):

Should be merged and released shortly, will update here

@vbarda commented on GitHub (Nov 18, 2024): Should be merged and released shortly, will update here
Author
Owner

@vbarda commented on GitHub (Nov 18, 2024):

@epistoteles @lucatrovato should be fixed in 2.0.3 -- let me know if you're still running into any issues

@vbarda commented on GitHub (Nov 18, 2024): @epistoteles @lucatrovato should be fixed in 2.0.3 -- let me know if you're still running into any issues
Author
Owner

@lucatrovato commented on GitHub (Nov 19, 2024):

@vbarda just tested and it works. Thanks a lot for addressing this so quickly.

@lucatrovato commented on GitHub (Nov 19, 2024): @vbarda just tested and it works. Thanks a lot for addressing this so quickly.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraph#310