langchain - ✅(Solved) Fix [langchain] Agent model nodes in factory.py don't propagate config to model_.ainvoke, breaking callback handlers [2 pull requests, 2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
langchain-ai/langchain#36393Fetched 2026-04-08 01:57:58
View on GitHub
Comments
2
Participants
2
Timeline
11
Reactions
0
Author
Participants
Timeline (top)
labeled ×3commented ×2cross-referenced ×2issue_type_added ×1

Error Message

Error Message and Stack Trace (if applicable)

No error is thrown - this is a silent failure where callbacks simply don't propagate.

Root Cause

Root cause location:

File: langchain/agents/factory.py
Functions: _execute_model_async (line ~1267), amodel_node (line ~1296)

Fix Action

Fix / Workaround

  • This is a bug, not a usage question.
  • I added a clear and descriptive title that summarizes this issue.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangChain rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).
  • This is not related to the langchain-community package.
  • I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS.

PR fix notes

PR #36428: fix(agents): propagate config to model_.ainvoke in agent model nodes

Description (problem / solution / changelog)

Fixes #36393

Propagate RunnableConfig to model_.ainvoke() in agent model nodes so callbacks are not dropped during execution. This ensures tracing and callback handlers work correctly for agent-based and nested LangGraph workflows.

How did you verify your code works?

  • Added a temporary CallbackHandler and confirmed on_llm_start / on_llm_end are triggered for agent LLM calls
  • Verified that request.config is populated from runtime.config
  • Tested with nested agents (subgraphs) to ensure callback propagation works end-to-end
  • Confirmed no regression in existing agent execution paths

Changed files

  • libs/langchain_v1/langchain/agents/factory.py (modified, +2/-1)
  • libs/langchain_v1/langchain/agents/middleware/types.py (modified, +1/-0)

PR #36466: fix(langchain): propagate config to model_.invoke and model_.ainvoke in agent nodes

Description (problem / solution / changelog)

Summary

Fixes #36393.

Both `execute_model_sync` and `execute_model_async` called `model.invoke` / `model.ainvoke` without forwarding the LangGraph `RunnableConfig`. Callbacks passed via `agent.invoke(config={"callbacks": [...]})` were silently dropped, making model calls invisible to Langfuse, OpenTelemetry, and any other callback-based tracing system.

Root cause: The execute functions receive a `ModelRequest` but never retrieved the ambient LangGraph config, so the model was invoked in a context-free environment with no callbacks.

Fix: Call `get_config()` from `langgraph.config` inside both `_execute_model_sync` and `_execute_model_async` and pass the result to the model invocation — a 2-line change. No public API changes, no new parameters, no changes to `ModelRequest` or `wrap_model_call` handler types.

Changes

Test plan

  • `test_callbacks_propagate_to_model_invoke` — fires with sync agent invocation
  • `test_callbacks_propagate_to_model_ainvoke` — fires with async agent invocation
  • Full agents suite: `pytest tests/unit_tests/agents/ -q` → 725 passed, 0 failures

AI disclosure: This fix was implemented with assistance from Claude Code (Anthropic). The root cause analysis, code change, and tests were reviewed and verified manually.

🤖 Generated with Claude Code

Changed files

  • libs/langchain_v1/langchain/agents/factory.py (modified, +3/-2)
  • libs/langchain_v1/tests/unit_tests/agents/test_config_propagation.py (added, +64/-0)

Code Example

"""
Minimal reproducible example showing that callbacks don't propagate 
through DeepAgent/agent model nodes in langchain.agents.factory.

This affects Langfuse tracing, OpenTelemetry instrumentation, and any 
other callback-based observability when using sub-agents or middleware.
"""
import asyncio
from typing import Any, Optional
from langchain.agents import create_react_agent
from langchain_core.callbacks import BaseCallbackHandler
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.messages import AIMessage


class TestCallbackHandler(BaseCallbackHandler):
    """Test handler that logs all LLM starts to verify callback propagation."""
    
    def __init__(self):
        self.llm_starts: list[dict] = []
    
    def on_llm_start(self, serialized: dict[str, Any], prompts: list[str], **kwargs) -> None:
        self.llm_starts.append({"serialized": serialized, "prompts": prompts})
        print(f"[CALLBACK] on_llm_start: {serialized.get('name', 'unknown')}")


async def main():
    # Create a simple mock model for testing
    class MockModel:
        async def ainvoke(self, messages, config=None, **kwargs):
            # Check if config was passed (this is what fails in factory.py)
            print(f"[MODEL] ainvoke called with config={config}")
            if config and config.get("callbacks"):
                print(f"[MODEL] config has {len(config['callbacks'])} callbacks")
            else:
                print("[MODEL] NO callbacks in config - THIS IS THE BUG")
            return AIMessage(content="test response")
        
        def bind_tools(self, tools, **kwargs):
            return self
    
    model = MockModel()
    
    # Create a simple ReAct agent
    tools = []
    prompt = ChatPromptTemplate.from_messages([
        ("system", "You are a helpful assistant."),
        ("placeholder", "{messages}"),
    ])
    
    agent = create_react_agent(model, tools, prompt=prompt)
    
    # Create callback handler
    handler = TestCallbackHandler()
    config = {"callbacks": [handler]}
    
    # Invoke the agent with callbacks
    print("=" * 60)
    print("Invoking agent with callback handler...")
    print("=" * 60)
    
    result = await agent.ainvoke(
        {"messages": [("human", "Hello")]},
        config=config
    )
    
    print("=" * 60)
    print(f"Callback handler recorded {len(handler.llm_starts)} LLM starts")
    print("=" * 60)
    
    if len(handler.llm_starts) == 0:
        print("\n❌ BUG CONFIRMED: Callbacks did NOT propagate to model_.ainvoke")
        print("The model node in factory.py doesn't pass config to model_.ainvoke()")
    else:
        print("\n✅ Callbacks propagated successfully")


if __name__ == "__main__":
    asyncio.run(main())

---

No error is thrown - this is a silent failure where callbacks simply don't propagate.

When tracing with Langfuse, you'll see:

Root trace created
Agent/Chain observations visible
Missing: LLM/GENERATION observations from model node (silent failure)
Callback handlers in config are ignored during model_.ainvoke()

---

async def _execute_model_async(messages, model_, **kwargs):  # Missing config param
    response = await model_.ainvoke(messages, **kwargs)  # Missing config=config

async def amodel_node(state, **kwargs):  # Missing config param
    return await _execute_model_async(messages, model_, **kwargs)
RAW_BUFFERClick to expand / collapse

Checked other resources

  • This is a bug, not a usage question.
  • I added a clear and descriptive title that summarizes this issue.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangChain rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).
  • This is not related to the langchain-community package.
  • I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS.

Package (Required)

  • langchain
  • langchain-openai
  • langchain-anthropic
  • langchain-classic
  • langchain-core
  • langchain-model-profiles
  • langchain-tests
  • langchain-text-splitters
  • langchain-chroma
  • langchain-deepseek
  • langchain-exa
  • langchain-fireworks
  • langchain-groq
  • langchain-huggingface
  • langchain-mistralai
  • langchain-nomic
  • langchain-ollama
  • langchain-openrouter
  • langchain-perplexity
  • langchain-qdrant
  • langchain-xai
  • Other / not sure / general

Related Issues / PRs

DeepAgents #2315 - Related config propagation issue Langfuse #10721 - Nested traces broken due to callback propagation issues https://github.com/langchain-ai/langchain/issues/30901 (config propagation in agent nodes)

Reproduction Steps / Example Code (Python)

"""
Minimal reproducible example showing that callbacks don't propagate 
through DeepAgent/agent model nodes in langchain.agents.factory.

This affects Langfuse tracing, OpenTelemetry instrumentation, and any 
other callback-based observability when using sub-agents or middleware.
"""
import asyncio
from typing import Any, Optional
from langchain.agents import create_react_agent
from langchain_core.callbacks import BaseCallbackHandler
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.messages import AIMessage


class TestCallbackHandler(BaseCallbackHandler):
    """Test handler that logs all LLM starts to verify callback propagation."""
    
    def __init__(self):
        self.llm_starts: list[dict] = []
    
    def on_llm_start(self, serialized: dict[str, Any], prompts: list[str], **kwargs) -> None:
        self.llm_starts.append({"serialized": serialized, "prompts": prompts})
        print(f"[CALLBACK] on_llm_start: {serialized.get('name', 'unknown')}")


async def main():
    # Create a simple mock model for testing
    class MockModel:
        async def ainvoke(self, messages, config=None, **kwargs):
            # Check if config was passed (this is what fails in factory.py)
            print(f"[MODEL] ainvoke called with config={config}")
            if config and config.get("callbacks"):
                print(f"[MODEL] config has {len(config['callbacks'])} callbacks")
            else:
                print("[MODEL] NO callbacks in config - THIS IS THE BUG")
            return AIMessage(content="test response")
        
        def bind_tools(self, tools, **kwargs):
            return self
    
    model = MockModel()
    
    # Create a simple ReAct agent
    tools = []
    prompt = ChatPromptTemplate.from_messages([
        ("system", "You are a helpful assistant."),
        ("placeholder", "{messages}"),
    ])
    
    agent = create_react_agent(model, tools, prompt=prompt)
    
    # Create callback handler
    handler = TestCallbackHandler()
    config = {"callbacks": [handler]}
    
    # Invoke the agent with callbacks
    print("=" * 60)
    print("Invoking agent with callback handler...")
    print("=" * 60)
    
    result = await agent.ainvoke(
        {"messages": [("human", "Hello")]},
        config=config
    )
    
    print("=" * 60)
    print(f"Callback handler recorded {len(handler.llm_starts)} LLM starts")
    print("=" * 60)
    
    if len(handler.llm_starts) == 0:
        print("\n❌ BUG CONFIRMED: Callbacks did NOT propagate to model_.ainvoke")
        print("The model node in factory.py doesn't pass config to model_.ainvoke()")
    else:
        print("\n✅ Callbacks propagated successfully")


if __name__ == "__main__":
    asyncio.run(main())

Error Message and Stack Trace (if applicable)

No error is thrown - this is a silent failure where callbacks simply don't propagate.

When tracing with Langfuse, you'll see:

Root trace created
Agent/Chain observations visible
Missing: LLM/GENERATION observations from model node (silent failure)
Callback handlers in config are ignored during model_.ainvoke()

Description

What is the problem?

Agent model nodes in langchain/agents/factory.py don't pass the config parameter to model_.ainvoke(), preventing callbacks from propagating through agent LLM calls when using sub-agents or middleware with LangGraph.

Current behavior:

In langchain/agents/factory.py:

  • _execute_model_async() doesn't accept a config parameter
  • amodel_node() doesn't accept or forward config
  • model_.ainvoke(messages, **kwargs) is called without config=config

This breaks callback propagation for:

  • Langfuse tracing (CallbackHandler)
  • OpenTelemetry instrumentation
  • Custom callback handlers
  • Any observability that relies on LangChain callbacks

Expected behavior:

Config should propagate through agent model nodes just like it does through regular LangGraph nodes, enabling callbacks to reach model invocations.

Root cause location:

File: langchain/agents/factory.py
Functions: _execute_model_async (line ~1267), amodel_node (line ~1296)

Current code (simplified):

async def _execute_model_async(messages, model_, **kwargs):  # Missing config param
    response = await model_.ainvoke(messages, **kwargs)  # Missing config=config

async def amodel_node(state, **kwargs):  # Missing config param
    return await _execute_model_async(messages, model_, **kwargs)

Impact:

This affects DeepAgents and any LangGraph architecture using:

  • Compiled subgraphs (compiled agents as nodes)
  • Sub-agents within parent graphs
  • Middleware patterns with agent nodes

Without this fix, LLM calls inside agents are "invisible" to tracing systems, making debugging and observability impossible for agent-based workflows.

System Info

System Information

OS: Linux/Mac/Windows Python: 3.12+

Package Information

langchain: 0.3.x langchain-core: 0.3.x
langgraph: 0.2.x

Other Dependencies:

langfuse: 2.x/3.x (for tracing reproduction)

extent analysis

TL;DR

The issue can be fixed by modifying the _execute_model_async and amodel_node functions in langchain/agents/factory.py to accept and forward the config parameter, enabling callback propagation through agent model nodes.

Guidance

  • Identify the _execute_model_async and amodel_node functions in langchain/agents/factory.py and modify them to accept a config parameter.
  • Update the _execute_model_async function to pass the config parameter to model_.ainvoke().
  • Verify that the config parameter is being passed correctly by adding print statements or using a debugger.
  • Test the modified code with the provided example to ensure that callbacks are propagating correctly.

Example

async def _execute_model_async(messages, model_, config=None, **kwargs):
    response = await model_.ainvoke(messages, config=config, **kwargs)

async def amodel_node(state, config=None, **kwargs):
    return await _execute_model_async(messages, model_, config, **kwargs)

Notes

The modifications should be made in the langchain/agents/factory.py file, specifically in the _execute_model_async and amodel_node functions. The config parameter should be added to the function signatures and passed to model_.ainvoke() to enable callback propagation.

Recommendation

Apply the workaround by modifying the _execute_model_async and amodel_node functions to accept and forward the config parameter, as this will enable callback propagation through agent model nodes and fix the issue.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

langchain - ✅(Solved) Fix [langchain] Agent model nodes in factory.py don't propagate config to model_.ainvoke, breaking callback handlers [2 pull requests, 2 comments, 2 participants]