I have a LangGraph agent that is supposed to interact with the user in multi-round conversations and perform modifications to a kubernetes environment. I am using an external Model Context Protocol server to provide the tools to interact with the k8s configuration and for now my agent construction is simply the LangChain create_agent function.
Now, the agent could use the tools incorrectly (e.g. attempting to delete a non-existant k8s pod) and the tool would raise a ToolException whose description could aid the model in refining its approach. Since the state of the agent requires a ToolMessage corresponding to each AIMessage that corresponds to a tool call I want to catch the exception and append its description as the response ToolMessage in the state of the agent. However, I am getting a hard-to-debug error that suggests I am going about this incorrectly.
Here is my agent code:
from langchain.agents import create_agent
from langchain_core.messages import BaseMessage
from langchain.messages import ToolMessage, AIMessage
from langgraph.graph import MessagesState
from langgraph.checkpoint.memory import InMemorySaver
from langchain.tools import ToolException
class MyAgent:
def __init__(self):
model = ...
tools = []
self.config = {...}
self.agent = create_agent(
model,
tools=tools,
state_schema=MessagesState,
checkpointer=InMemorySaver()
)
def run(self,cmd:dict) -> BaseMessage:
try:
result = self.agent.invoke(cmd,self.config)
return result["messages"][-1]
except ToolException as expt:
# ERROR HANDLING
# get state snapshot to find out tool call id
snapshot = self.agent.get_state(self.config)
last_tool_call = snapshot.values["messages"][-1].tool_calls[0]
# compose toolmessage to signal the error
error_tool_message = ToolMessage(
content=f"Couldn't execute tool because of: {expt}",
tool_call_id=last_tool_call["id"]
)
# ERROR COMES FROM HERE
# update the state
self.agent.update_state(
self.config,
{"messages":[error_tool_message]}
)
# return error notification to the user
return AIMessage(
f"Couldn't execute because of tool error: {expt}"
)
When I try to run the agent with a message that asks it to delete a non-existent pod I get the following error message:
Traceback (most recent call last):
File "/home/ubuntu/dev/elster/src/elster/agent.py", line 144, in run
result = self.event_loop.run_until_complete(
self.agent.ainvoke(cmd,config=self.config)
)
File "/home/ubuntu/.local/share/uv/python/cpython-3.13.9-linux-x86_64-gnu/lib/python3.13/asyncio/base_events.py", line 725, in run_until_complete
return future.result()
~~~~~~~~~~~~~^^
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langgraph/pregel/main.py", line 3182, in ainvoke
async for chunk in self.astream(
...<29 lines>...
chunks.append(chunk)
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langgraph/pregel/main.py", line 3000, in astream
async for _ in runner.atick(
...<13 lines>...
yield o
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langgraph/pregel/_runner.py", line 304, in atick
await arun_with_retry(
...<15 lines>...
)
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langgraph/pregel/_retry.py", line 137, in arun_with_retry
return await task.proc.ainvoke(task.input, config)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langgraph/_internal/_runnable.py", line 705, in ainvoke
input = await asyncio.create_task(
^^^^^^^^^^^^^^^^^^^^^^^^^^
step.ainvoke(input, config, **kwargs), context=context
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langgraph/_internal/_runnable.py", line 473, in ainvoke
ret = await self.afunc(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langchain/tools/tool_node.py", line 733, in _afunc
outputs = await asyncio.gather(*coros)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langchain/tools/tool_node.py", line 1066, in _arun_one
return await self._execute_tool_async(tool_request, input_type, config)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langchain/tools/tool_node.py", line 1015, in _execute_tool_async
content = _handle_tool_error(e, flag=self._handle_tool_errors)
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langchain/tools/tool_node.py", line 389, in _handle_tool_error
content = flag(e) # type: ignore [assignment, call-arg]
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langchain/tools/tool_node.py", line 352, in _default_handle_tool_errors
raise e
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langchain/tools/tool_node.py", line 970, in _execute_tool_async
response = await tool.ainvoke(call_args, config)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langchain_core/tools/structured.py", line 63, in ainvoke
return await super().ainvoke(input, config, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langchain_core/tools/base.py", line 601, in ainvoke
return await self.arun(tool_input, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langchain_core/tools/base.py", line 969, in arun
raise error_to_raise
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langchain_core/tools/base.py", line 938, in arun
response = await coro_with_context(coro, context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langchain_core/tools/structured.py", line 117, in _arun
return await self.coroutine(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langchain_mcp_adapters/tools.py", line 292, in call_tool
return _convert_call_tool_result(call_tool_result)
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langchain_mcp_adapters/tools.py", line 80, in _convert_call_tool_result
raise ToolException(tool_content)
langchain_core.tools.base.ToolException: failed to delete pod aaa in namespace : pods "aaa" not found
During task with name 'tools' and id '8fb89a71-87c5-ea74-9154-9fbc2b3b2503'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/ubuntu/.local/share/uv/python/cpython-3.13.9-linux-x86_64-gnu/lib/python3.13/runpy.py", line 198, in _run_module_as_main
return _run_code(code, main_globals, None,
"__main__", mod_spec)
File "/home/ubuntu/.local/share/uv/python/cpython-3.13.9-linux-x86_64-gnu/lib/python3.13/runpy.py", line 88, in _run_code
exec(code, run_globals)
~~~~^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/.vscode-server/extensions/ms-python.debugpy-2025.14.1-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/__main__.py", line 71, in <module>
cli.main()
~~~~~~~~^^
File "/home/ubuntu/.vscode-server/extensions/ms-python.debugpy-2025.14.1-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/../debugpy/server/cli.py", line 508, in main
run()
~~~^^
File "/home/ubuntu/.vscode-server/extensions/ms-python.debugpy-2025.14.1-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/../debugpy/server/cli.py", line 358, in run_file
runpy.run_path(target, run_name="__main__")
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/.vscode-server/extensions/ms-python.debugpy-2025.14.1-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 310, in run_path
return _run_module_code(code, init_globals, run_name, pkg_name=pkg_name, script_name=fname)
File "/home/ubuntu/.vscode-server/extensions/ms-python.debugpy-2025.14.1-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 127, in _run_module_code
_run_code(code, mod_globals, init_globals, mod_name, mod_spec, pkg_name, script_name)
~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/.vscode-server/extensions/ms-python.debugpy-2025.14.1-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 118, in _run_code
exec(code, run_globals)
~~~~^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/dev/elster/src/elster/main.py", line 104, in <module>
main()
~~~~^^
File "/home/ubuntu/dev/elster/src/elster/main.py", line 97, in main
msg = agent.run(cmd)["messages"][-1]
~~~~~~~~~^^^^^
File "/home/ubuntu/dev/elster/src/elster/agent.py", line 155, in run
self.agent.update_state(self.config,{"messages":[error_tool_message]})
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langgraph/pregel/main.py", line 2359, in update_state
return self.bulk_update_state(config, [[StateUpdate(values, as_node, task_id)]])
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langgraph/pregel/main.py", line 1883, in bulk_update_state
current_config = perform_superstep(current_config, superstep)
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langgraph/pregel/main.py", line 1818, in perform_superstep
run.invoke(
~~~~~~~~~~^
values,
^^^^^^^
...<23 lines>...
),
^^
)
^
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langchain_core/runnables/base.py", line 3090, in invoke
input_ = context.run(step.invoke, input_, config)
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langgraph/_internal/_runnable.py", line 400, in invoke
ret = self.func(*args, **kwargs)
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langgraph/graph/_branch.py", line 167, in _route
return self._finish(writer, input, result, config)
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/dev/elster/.venv/lib/python3.13/site-packages/langgraph/graph/_branch.py", line 203, in _finish
r if isinstance(r, Send) else self.ends[r] for r in result
~~~~~~~~~^^^
KeyError: 'model'
What am I doing incorrectly here?