Skip to content

fix(langchain): propagate root trace attributes to child runs under ainvoke - #2068

Merged
hassiebp merged 1 commit into
mainfrom
hassiebbot/langchain-async-session-propagation-b254
Oct 28, 2026
Merged

hassiebp merged 1 commit into
mainfrom
hassiebbot/langchain-async-session-propagation-b254

Conversation

@hassiebp

@hassiebp hassiebp commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

What does this PR do?

When trace attributes are passed through LangChain invocation metadata (config={"metadata": {"langfuse_session_id": ...}}) and the runnable is called with ainvoke, only the root observation got session_id (and user_id, tags, trace_name, propagated metadata). Every child generation, tool and chain had none, so those observations dropped out of session-scoped views such as the Sessions page tool filters. Sync invoke and an explicit propagate_attributes(...) wrapper both worked.

Root cause: CallbackHandler is a sync handler with run_inline=False. In async runs LangChain calls it via run_in_executor(None, copy_context().run, ...), so each callback runs in a fresh copy of the caller's context. The root on_chain_start enters propagate_attributes, but that context change stays in the root callback's copy, so the child callbacks never see it and their spans start without the propagated keys.

Fix:

  • The root run stores the OTel context it built after entering propagate_attributes on _RootRunState.propagation_context.
  • Child start_observation calls (chain, tool, retriever, LLM) run inside _use_root_propagated_attributes. It fills in only the langfuse.propagated.* keys that are missing from the current context. Scalar values already set in the current context win, and metadata/tags are merged. If nothing differs, nothing is attached, so the sync path does not change.

Fixes LFE-17917

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Refactor
  • Documentation update
  • Tooling, CI, or repo maintenance

Verification

test_root_chain_metadata_propagates_session_id_to_children_on_ainvoke failed before the fix (KeyError: 'session.id' on ChatPromptTemplate) and passes after it. test_child_run_keeps_attributes_propagated_in_its_own_context checks that a child's own propagate_attributes still wins over the root value.

uv run --frozen ruff check .                       # All checks passed!
uv run --frozen mypy langfuse --no-error-summary   # exit 0
uv run --frozen pytest -n auto tests/unit/test_langchain.py tests/unit/test_langchain_utils.py   # 31 passed
uv run --frozen pytest -n auto --dist worksteal tests/unit   # 974 passed, 2 skipped

I did not run e2e or live-provider tests. The behavior is covered by unit tests with the in-memory exporter.

Checklist

  • I self-reviewed the diff using code_review.md.
  • I added or updated tests for behavior changes.
  • I updated docs, examples, or .env.template if needed. (Not needed: this brings async in line with the documented behavior.)
  • I did not hand-edit generated files; if generated files changed, I used the upstream regeneration path.
  • I did not commit secrets or credentials.
Open in Web Open in Cursor 

RetriggerView in GreptileConfidence Score: 4/5

Fix the remaining async session override case before merging.

Summary

Saves the root chain's propagated attributes and makes them available while child observations start.

  • Async LangChain child observations inherit root trace attributes.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A["Caller context: session outer"] --> B["Root callback: invocation sets session inner"]
  B --> C["Save root context"]
  A --> D["Async child callback inherits session outer"]
  C --> E["Merge saved root attributes"]
  D --> E
  E --> F["Existing value wins: child keeps session outer"]
Loading

Reviews (1) · Last reviewed commit: "fix(langchain): propagate root trace att..." · Reviewed by Greptile

…invoke

Co-authored-by: hassieb.pakzad <hassieb.pakzad@clickhouse.com>
@github-actions

Copy link
Copy Markdown

@claude review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-28T09:57:23.118356Z 9c582ab PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

No review was started: this request came from a bot account. Manual reviews can only be requested by someone with write access to this repository. Ask a maintainer to comment @claude review, or have your automation post the comment from a user account with write access.

Tip: disable this comment in your organization's Code Review settings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9c582abcd8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread langfuse/langchain/CallbackHandler.py
Comment thread langfuse/langchain/CallbackHandler.py

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.

Comment thread langfuse/langchain/CallbackHandler.py
@hassiebp
hassiebp merged commit 80a41c4 into main Oct 28, 2026
25 checks passed
@hassiebp
hassiebp deleted the hassiebbot/langchain-async-session-propagation-b254 branch October 28, 2026 12:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants