fix(langgraph): keep context values out of tracer-derived metadata (#2690)
Values passed via `context` were reaching LangSmith as `extra.metadata`. On Platform the Agent Server mirrors `context` into `configurable` (`run.py`, *"keep config and context in sync for user provided params"*), and `_getTracingMetadataDefaults` promoted every `configurable` entry whose value passes the primitive-type check in `_excludeAsMetadata` — so data callers deliberately routed through the non-persisted, non-traced channel was traced anyway, on the root run and on `__start__` and every node run. ## Changes - `_getTracingMetadataDefaults` now recognizes context aliases: a `configurable` entry that is an own property of `config.context` with an `Object.is`-equal value is treated as context-provenance, not user metadata. - Aliased keys emit `metadata[key] = undefined` rather than being omitted. `LangChainTracer` merges tracing metadata first-wins, so the root marker also stops `@langchain/core`'s own configurable promotion from re-adding the key on child task and node runs — the path that actually leaked. `undefined` drops out on serialization. - Widened the helper's parameter to `LangGraphRunnableConfig` so `config.context` is visible; internal `__`-prefixed keys are never marked. - Configurable-only values, values that differ from their context counterpart, explicit `metadata`, and the platform identity keys (`thread_id`, `run_id`, `assistant_id`, `graph_id`) are all unaffected. ## Testing Replaced the tracing tests' `FakeTracer` with a `LangChainTracer` backed by a stubbed client that captures real `createRun` payloads. `tracerInheritableMetadata` is only applied to `LangChainTracer` instances, so a `BaseTracer` subclass cannot observe this channel at all — the assertions now run against the same metadata LangSmith would receive, across all three runs (`LangGraph`, `__start__`, node). ## Follow-up required — this half is inert alone Verified end-to-end against the public `langchain/langgraphjs-api:0.12.2-node24` image with this build installed in the deployed graph: | Configuration | context delivered | tracer metadata leak | |---|---|---| | public image, this fix | no — sidecar strips `context` | n/a, suppression cannot fire | | public image + sidecar forwarding `context`, this fix | yes | absent | | public image + sidecar forwarding `context`, published `1.3.7` | yes | present on `__start__` and node runs | The sidecar's `StreamEventsPayload` (`langgraph_api/js/client.mts`) has no `context` field, so zod strips it and `config.context` is `undefined` inside the graph. A matching `langgraph-api` change is needed for this fix to take effect in production; it will be opened separately. Separately out of scope: the Python `run.py` backfill still mirrors `context` into `configurable`, and that mirrored copy is persisted in thread state and checkpoint metadata. Different channel, pre-existing by design.
S
Saad Farooq committed
00f68a1b002d820b95129bcdaf387d2678ead6f0
Parent: 841466e
Committed by GitHub <noreply@github.com>
on 8/14/2026, 6:28:36 PM