getsentry / getsentry/sentry-javascript

`instrumentLangGraph` and `createLangChainCallbackHandler` silently drop spans when used together

Đang mở
#19,627 1 bình luận 0 reaction 0 người được giao Xem trên GitHub
Browser Bug
Ngôn ngữ chính
TypeScript
Star
8.7k
Fork
1.8k
Merge trung bình
1 ngày 17 giờ
Pull request đã merge (30 ngày)
515

Mô tả

### Is there an existing issue for this?

- [x] I have checked for existing issues https://github.com/getsentry/sentry-javascript/issues
- [x] I have reviewed the documentation https://docs.sentry.io/
- [x] I am using the latest SDK release https://github.com/getsentry/sentry-javascript/releases

### How do you use Sentry?

Sentry Saas (sentry.io)

### Which SDK are you using?

@sentry/browser

### SDK Version

^10.40.0

### Framework Version

_No response_

### Link to Sentry event

https://pri-dogfooding-ai.sentry.io/insights/ai-agents/?project=4510951776059472&statsPeriod=30d&trace=043dd6239e7645d9b70f641fe3ec2f83&span=undefined&trace-timestamp=1772622191

### Reproduction Example/SDK Setup

_No response_

### Steps to Reproduce

```js
const graph = new StateGraph(IdeaState)
.addNode("expand", expandNode) // calls llm.invoke()
.addNode("validate", validateNode) // calls llm.invoke()
.addNode("differentiate", diffNode) // calls llm.invoke()
.addNode("roadmap", roadmapNode) // calls llm.invoke()
.addNode("pitch", pitchNode) // calls llm.invoke()
.addEdge(START, "expand")
.addEdge("expand", "validate")
.addEdge("validate", "differentiate")
.addEdge("differentiate", "roadmap")
.addEdge("roadmap", "pitch")
.addEdge("pitch", END);

Sentry.instrumentLangGraph(graph, { recordInputs: true, recordOutputs: true });
const compiled = graph.compile({ name: "idea-forge" });

const sentryHandler = Sentry.createLangChainCallbackHandler({
recordInputs: true,
recordOutputs: true,
});
const result = await compiled.invoke({ idea: "test" }, { callbacks: [sentryHandler] });
```

### Expected Result

All 5 LLM calls should produce `chat` spans in the trace.

### Actual Result

| Setup | `chat` spans captured |
|-------|----------------------|
| `instrumentLangGraph` + `createLangChainCallbackHandler` | **1 out of 5** |
| `createLangChainCallbackHandler` only | 5 out of 5 |
| `instrumentLangGraph` only | 0 (expected — no callback handler) |

4 out of 5 `chat` spans are silently dropped with no error or warning.

Additionally, the trace contains multiple spurious nested `invoke_agent` sub-spans with near-zero durations (0.20ms) that should not exist:

```
invoke_agent idea-forge 7.43s ← top-level (expected)
invoke_agent idea-forge 2.70ms ← spurious
invoke_agent idea-forge 1.60ms ← spurious
invoke_agent idea-forge 0.20ms ← spurious
invoke_agent idea-forge 4.41s
chat claude-haiku-4-5-20251001 4.41s ← only 1 of 5 chat spans
invoke_agent idea-forge 0.20ms ← spurious
invoke_agent idea-forge 0.20ms ← spurious
```

### Additional Context

**Possible Root Cause:**

`instrumentLangGraph` wraps `invoke()` inside `Sentry.startSpan()`. As async execution passes through sequential nodes, the span context from `startSpan` is not consistently maintained across all node invocations. Some `handleChatModelStart` callbacks from the handler fire outside an active span context and their spans are dropped.

### Priority

React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding `+1` or `me too`, to help us triage it.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.