@xuro-langchain Thanks a lot for your reply — that really helped!
Later I realized your suggestion was already in the documentation (my bad
): Middleware - Docs by LangChain
Now I’m running into a related issue: INVALID_CONCURRENT_GRAPH_UPDATE - Docs by LangChain
I have a hypothesis that since all my SubAgents share the same CustomMiddleware and CustomState (AgentState) schema — even for values that don’t change — there might be some concurrency when the subgraphs “return” and try to rewrite the same values in the shared ‘main graph’ state.
Here’s an example of the error I’m seeing:
InvalidUpdateError("At key 'load_id': Can receive only one value per step. Use an Annotated key to handle multiple values.\nFor troubleshooting, visit: https://docs.langchain.com/oss/python/langgraph/errors/INVALID_CONCURRENT_GRAPH_UPDATE")Traceback (most recent call last):
File "/usr/local/lib/python3.12/site-packages/langgraph/pregel/main.py", line 2689, in stream
loop.after_tick()
File "/usr/local/lib/python3.12/site-packages/langgraph/pregel/_loop.py", line 545, in after_tick
self.updated_channels = apply_writes(
^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/langgraph/pregel/_algo.py", line 294, in apply_writes
if channels[chan].update(vals) and next_version is not None:
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/langgraph/channels/last_value.py", line 64, in update
raise InvalidUpdateError(msg)
langgraph.errors.InvalidUpdateError: At key 'load_id': Can receive only one value per step. Use an Annotated key to handle multiple values.
For troubleshooting, visit: https://docs.langchain.com/oss/python/langgraph/errors/INVALID_CONCURRENT_GRAPH_UPDATE
Note: The load_id attribute (from my custom state) never changes.
Does that theory make sense?
If so:
-
Is the recommended fix (as mentioned in the docs) to create a reducer, maybe to safely replace or merge the state values?
-
In this case, order isn’t really an issue because the value doesn’t change — but for other state fields it might be. What are the best practices around handling this kind of concurrency in shared state?