How to Fix 'chain execution stuck during development' in LangChain (Python)

By Cyprian AaronsUpdated 2026-04-21
chain-execution-stuck-during-developmentlangchainpython

When LangChain says your chain execution is “stuck during development,” it usually means the run is waiting on something that never returns: a missing input, a blocking tool call, an async/sync mismatch, or a callback handler that never finishes. In practice, this shows up when you call chain.invoke() or chain.stream() and the process just sits there with no output.

This is usually not a LangChain bug. It’s almost always a chain wiring problem, a tool that hangs, or code that works in notebooks but blocks in a real Python process.

The Most Common Cause

The #1 cause is a tool or runnable that blocks forever because it expects input you never provide, or because you mixed sync and async execution incorrectly.

A very common pattern is using an async chain or tool inside synchronous code without awaiting it properly, or calling a tool that waits for user input during chain execution.

Broken vs fixed

Broken patternRight pattern
Calls an async runnable from sync code and never awaits itUse asyncio.run() or stay fully synchronous
Uses input() inside a toolPass data into the tool as arguments
Hangs inside AgentExecutor because a tool never returnsMake the tool deterministic and bounded
# BROKEN
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate

@tool
def ask_user(question: str) -> str:
    # This will block forever in server/dev runs waiting for stdin
    return input(question + " ")

llm = ChatOpenAI(model="gpt-4o-mini")
tools = [ask_user]

prompt = ChatPromptTemplate.from_messages([
    ("system", "You are helpful."),
    ("human", "{input}")
])

agent = create_tool_calling_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools)

# Hangs during development if the agent calls ask_user()
result = executor.invoke({"input": "What is my account number?"})
print(result)
# FIXED
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate

@tool
def lookup_account(customer_id: str) -> str:
    # Deterministic, bounded work only
    return f"Account lookup for {customer_id}: OK"

llm = ChatOpenAI(model="gpt-4o-mini")
tools = [lookup_account]

prompt = ChatPromptTemplate.from_messages([
    ("system", "You are helpful."),
    ("human", "{input}")
])

agent = create_tool_calling_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools)

result = executor.invoke({"input": "Check customer 12345"})
print(result)

If your chain uses async components, keep the whole path async:

import asyncio

async def main():
    result = await executor.ainvoke({"input": "Check customer 12345"})
    print(result)

asyncio.run(main())

Other Possible Causes

1) A tool has no timeout and is waiting on network I/O

If your custom tool calls an API without a timeout, the chain can sit there forever.

# BAD: no timeout
requests.get("https://internal-api.example.com/customer/123")

# GOOD: bounded request
requests.get(
    "https://internal-api.example.com/customer/123",
    timeout=10,
)

If you’re using httpx, do the same:

client = httpx.Client(timeout=10.0)

2) Recursive agent loops with no stop condition

Agents can loop when the model keeps selecting tools and never produces a final answer. You’ll often see repeated AgentExecutor activity with no termination.

executor = AgentExecutor(
    agent=agent,
    tools=tools,
    max_iterations=3,
    early_stopping_method="generate",
)

Without limits, the agent may keep running until it looks “stuck.”

3) Callback handlers blocking execution

Custom callbacks can freeze execution if they do slow file I/O or network calls in on_llm_new_token, on_chain_end, or similar hooks.

from langchain_core.callbacks import BaseCallbackHandler

class SlowHandler(BaseCallbackHandler):
    def on_llm_new_token(self, token: str, **kwargs):
        # BAD: writing every token synchronously to slow storage
        write_to_remote_log(token)

Keep callback handlers lightweight. Push events to an async queue or local buffer instead.

4) Missing environment variables causing retry loops

Some integrations don’t fail loudly at first. They retry requests and look like they’re hanging.

import os

assert os.getenv("OPENAI_API_KEY"), "OPENAI_API_KEY is missing"

Also check provider-specific vars like:

  • LANGSMITH_API_KEY
  • ANTHROPIC_API_KEY
  • proxy settings like HTTP_PROXY / HTTPS_PROXY

How to Debug It

  1. Reduce to the smallest runnable chain

    • Remove agents first.
    • Remove tools next.
    • Test a plain ChatOpenAI.invoke() call.
    • If this works, the problem is in your orchestration layer.
  2. Add timeouts everywhere

    • HTTP clients.
    • Database queries.
    • Tool wrappers.
    • External SDKs.
  3. Print each step before and after execution

    • Log before calling invoke().
    • Log inside every custom tool.
    • Log inside callback handlers.
    • If you see “before” but not “after,” you found the blocking point.
print("before invoke")
result = executor.invoke({"input": "test"})
print("after invoke")
  1. Turn on LangSmith tracing
    • This helps identify where the run stops.
    • You’ll see whether it hangs in the LLM call, agent planning step, or tool execution.

Typical signs:

  • Repeated agent actions with no final output.
  • A single tool run that never completes.
  • A callback event that starts but never ends.

Prevention

  • Keep tools deterministic and bounded.

    • No input().
    • No infinite loops.
    • No unbounded retries.
  • Use explicit timeouts on every external dependency.

    • HTTP clients.
    • DB drivers.
    • SDK calls.
  • Separate sync and async paths cleanly.

    • Use invoke() for sync chains.
    • Use ainvoke() with asyncio.run() for async chains.

If you hit this error in development, assume one thing first: something in your chain is waiting forever. Start by removing tools and callbacks until the hang disappears, then add pieces back one by one. That gets you to the real root cause faster than staring at LangChain stack traces.


Keep learning

By Cyprian Aarons, AI Consultant at Topiax.

Want the complete 8-step roadmap?

Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.

Get the Starter Kit

Related Guides