Python
The following outlines common causes for “split” traces when building with python.Context propagation using asyncio
When using async calls (especially with streaming) in Python versions < 3.11, you may encounter issues with trace nesting. This is because Python’sasyncio
only added full support for passing context in version 3.11.
Why
LangChain and LangSmith SDK use contextvars to propagate tracing information implicitly. In Python 3.11 and above, this works seamlessly. However, in earlier versions (3.8, 3.9, 3.10),asyncio
tasks lack proper contextvar
support, which can lead to disconnected traces.
To resolve
- Upgrade Python Version (Recommended) If possible, upgrade to Python 3.11 or later for automatic context propagation.
-
Manual Context Propagation If upgrading isn’t an option, you’ll need to manually propagate the tracing context. The method varies depending on your setup:
a) Using LangGraph or LangChain Pass the parent
config
to the child call:b) Using LangSmith Directly Pass the run tree directly:c) Combining Decorated Code with LangGraph/LangChain Use a combination of techniques for manual handoff:
Context propagation using threading
It’s common to start tracing and want to apply some parallelism on child tasks all within a single trace. Python’s stdlibThreadPoolExecutor
by default breaks tracing.
Why
Python’s contextvars start empty within new threads. Here are two approaches to handle maintain trace contiguity:To resolve
-
Using LangSmith’s ContextThreadPoolExecutor
LangSmith provides a
ContextThreadPoolExecutor
that automatically handles context propagation: -
Manually providing the parent run tree
Alternatively, you can manually pass the parent run tree to the inner function:
get_current_run_tree()
to obtain the current run tree and pass it to the inner function using the langsmith_extra
parameter.
Both methods ensure that the inner function calls are correctly aggregated under the initial trace stack, even when executed in separate threads.