fix(langchain): pass trace_name to propagate_attributes in on_chain_start#1610
Open
STHITAPRAJNAS wants to merge 1 commit intolangfuse:mainfrom
Open
fix(langchain): pass trace_name to propagate_attributes in on_chain_start#1610STHITAPRAJNAS wants to merge 1 commit intolangfuse:mainfrom
STHITAPRAJNAS wants to merge 1 commit intolangfuse:mainfrom
Conversation
…tart When CallbackHandler.on_chain_start fires at the root of a chain (parent_run_id is None), propagate_attributes was called without a trace_name, so the trace name was determined by whichever internal node's on_chain_start happened to fire first. On LangGraph resume (e.g. after a human-in-the-loop interrupt) that node is often an internal subgraph whose name is "", which produces a blank trace name. The fix passes span_name — the name already computed from the serialized runnable and kwargs — as trace_name to propagate_attributes. This ensures the trace name is always pinned to the root chain's name regardless of execution order on resume. As a companion change, _parse_langfuse_trace_attributes now also reads a langfuse_trace_name key from LangChain metadata, consistent with the existing langfuse_session_id / langfuse_user_id / langfuse_tags pattern. When present, metadata langfuse_trace_name takes priority over the computed span_name. The key is also added to the strip-list in _strip_langfuse_keys_from_dict so it does not leak into observation metadata. Fixes langfuse#1602
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When
CallbackHandler.on_chain_startfires at the root of a LangChain/LangGraph run (parent_run_id is None), it callspropagate_attributes()without settingtrace_name. This means the trace name is determined by whichever internal node'son_chain_starthappens to fire first — which is non-deterministic on LangGraph resume.On initial run the first event usually comes from the root graph, so the name is correct. On resume (e.g. after
Command(resume=...)following a human-in-the-loop interrupt), the firston_chain_startcan fire from an internal subgraph whose name is"", producing a blank trace name.The
propagate_attributes()API already acceptstrace_name— it just wasn't being used.Fixes #1602.
Changes
langfuse/langchain/CallbackHandler.pyon_chain_start— passestrace_name=parsed_trace_attributes.get("trace_name") or span_nametopropagate_attributes().span_nameis already computed fromserialized+kwargs["name"](same value used as the span name), so this pins the trace name to the root chain name regardless of which internal node fires first on resume._parse_langfuse_trace_attributes— adds support for alangfuse_trace_namekey in LangChain metadata, following the same pattern aslangfuse_session_id/langfuse_user_id/langfuse_tags. When set, it takes priority over the computedspan_name._strip_langfuse_keys_from_dict— addslangfuse_trace_nameto the list of keys stripped from observation metadata (consistent with how the otherlangfuse_*trace-attribute keys are handled).Tests
Added
tests/test_langchain_callback_unit.py— 12 unit tests covering:_parse_langfuse_trace_attributesextracts / ignores / falls back onlangfuse_trace_nameon_chain_startcallspropagate_attributeswith the correcttrace_name(from serialized, from kwargs, from metadata override)propagate_attributesis NOT called for child runs_strip_langfuse_keys_from_dictstripslangfuse_trace_namecorrectlyAll tests use
unittest.mock— no API keys or network calls required.Disclaimer: Experimental PR review
Greptile Summary
This PR fixes a non-deterministic trace naming bug in the LangChain
CallbackHandler: on LangGraph resume,on_chain_startwas firing from internal subgraphs before the root, causingpropagate_attributes()to be called without atrace_nameand picking up a blank or wrong name. The fix pinstrace_nameto the root chain'sspan_name(with a newlangfuse_trace_namemetadata key for user overrides) and addslangfuse_trace_nameto the stripped-keys list so it does not leak into span metadata._parse_langfuse_trace_attributes: Extractslangfuse_trace_namestring from metadata, following the same pattern aslangfuse_session_id/langfuse_user_id.on_chain_start: Passestrace_name=parsed_trace_attributes.get("trace_name") or span_nametopropagate_attributes(), correctly prioritising an explicit metadata override over the computed span name._strip_langfuse_keys_from_dict: Addslangfuse_trace_nameto the list of trace-attribute keys removed from span metadata.Confidence Score: 5/5
Safe to merge — the fix is targeted, logically correct, and well-covered by tests.
All findings are P2 style issues (unused imports, misleading docstring). No logic, correctness, or security issues found. The core fix correctly uses the existing trace_name parameter of propagate_attributes, and the fallback expression (
parsed_trace_attributes.get("trace_name") or span_name) is safe because get_langchain_run_name always returns at least "" — it never produces an empty string.No files require special attention; the two unused imports in the test file are cosmetic only.
Important Files Changed
Sequence Diagram
sequenceDiagram participant LC as LangChain/LangGraph participant CH as CallbackHandler participant PA as propagate_attributes LC->>CH: on_chain_start(serialized, inputs, parent_run_id=None) CH->>CH: span_name = get_langchain_run_name(serialized, **kwargs) CH->>CH: _parse_langfuse_trace_attributes(metadata, tags) Note over CH: Extracts langfuse_trace_name (if present & string) CH->>PA: propagate_attributes(trace_name = metadata_trace_name OR span_name, ...) Note over PA: trace_name is now deterministic — Note over PA: always the root chain's name PA-->>CH: context manager entered CH->>LC: span started Note over LC,CH: On LangGraph resume (before fix) LC->>CH: on_chain_start(internal_subgraph, parent_run_id=None) CH->>PA: propagate_attributes(trace_name=NOT_SET) Note over PA: ⚠ blank/wrong trace name Note over LC,CH: On LangGraph resume (after fix) LC->>CH: on_chain_start(internal_subgraph, parent_run_id=None) CH->>CH: span_name = get_langchain_run_name(serialized) → root graph name CH->>PA: propagate_attributes(trace_name=span_name) Note over PA: ✅ trace name is always pinnedReviews (1): Last reviewed commit: "fix(langchain): pass trace_name to propa..." | Re-trigger Greptile
(2/5) Greptile learns from your feedback when you react with thumbs up/down!