I'm experiencing an intermittent error in my LangGraph-based agent system. The error occurs in my main agent class, which uses other custom agents as its tools. The error doesn't happen every time, but it occurs frequently enough to be a significant issue.
Here's the error I'm seeing:
An error occurred: local variable 'fut' referenced before assignment
Traceback (most recent call last):
...
File "/Users/yosef/uni/Uni chat store/llm/agents.py", line 326, in run
return self.build().graph.invoke({'messages': [HumanMessage(content=messages)]})['messages'][-1].content
File "/Users/yosef/uni/Uni chat store/venv/lib/python3.10/site-packages/langgraph/pregel/__init__.py", line 1448, in invoke
for chunk in self.stream(
File "/Users/yosef/uni/Uni chat store/venv/lib/python3.10/site-packages/langgraph/pregel/__init__.py", line 980, in stream
del fut, task
UnboundLocalError: local variable 'fut' referenced before assignment
here is my agent class
class AgentState(TypedDict):
messages: Annotated[list[AnyMessage], operator.add]
class Agent:
def __init__(self, model, tools, system="", print_tool_result=False):
self.system = system
graph = StateGraph(AgentState)
graph.add_node("llm", self.call_openai)
graph.add_node("action", self.take_action)
graph.add_conditional_edges(
"llm",
self.exists_action,
{True: "action", False: END}
)
graph.add_edge("action", "llm")
graph.set_entry_point("llm")
self.graph = graph.compile()
self.graph.step_timeout = 10
self.tools = {t.name: t for t in tools}
self.model = model.bind_tools(tools)
self.print_tool_result = print_tool_result
def exists_action(self, state: AgentState):
result = state['messages'][-1]
return len(result.tool_calls) > 0
def call_openai(self, state: AgentState):
messages = state['messages']
if self.system:
messages = [SystemMessage(content=self.system)] + messages
message = self.model.invoke(messages)
return {'messages': [message]}
def take_action(self, state: AgentState):
tool_calls = state['messages'][-1].tool_calls
results = []
for t in tool_calls:
print(f"Calling: {t}")
if not t['name'] in self.tools: # check for bad tool name from LLM
print("\n ....bad tool name....")
result = "bad tool name, retry" # instruct LLM to retry if bad
else:
result = self.tools[t['name']].invoke(input=t['args'])
if self.print_tool_result:
# print in blue
print(f"\033[94m{result}\033[0m")
results.append(ToolMessage(tool_call_id=t['id'], name=t['name'], content=str(result)))
print("Back to the model!")
return {'messages': results}
I've tried the following:
Upgraded to the latest version of LangGraph
Changed print statements to logging
This issue occurs because the step_timeout is set to a short duration for CompiledGraph. It can be reproduced, for example, by following the step_timeout example provided in the migration guide for the LangGraph's AgentExecutor. The cause lies in setting a timeout for concurrent.futures.wait, which allows the subsequent process to continue even if no tasks have been completed, i.e., even if done is an empty set. Since done is an empty set, the else processing triggers an UnboundLocalError.
I perceive this as a bug in the LangGraph library. To avoid this, it is necessary to include the process of exiting the while loop when done is an empty set before the for loop. As a temporary workaround, please set step_timeout to a longer duration or avoid setting it altogether.