Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ describe('LangGraph integration', () => {
createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createRunner, test) => {
test('should instrument LangGraph with default PII settings', async () => {
await createRunner()
.ignore('event')

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fix lacks error-path regression test

Low Severity

This fix PR does not add a test that covers the regression. The integration tests only drop .ignore('event') on success-path scenarios, so they would still pass if captureException were restored. A fix PR needs a unit, integration, or E2E test that fails without the change and passes with it: invoke that throws, the caller catching it, and no error event being sent. The related LangChain tests already follow that pattern with an error-model invoke inside try/catch.

Fix in Cursor Fix in Web

Triggered by project rule: PR Review Guidelines for Cursor Bot

Reviewed by Cursor Bugbot for commit 1d2b83c. Configure here.

.expect({ transaction: { transaction: 'langgraph-test' } })
.expect({
span: container => {
Expand Down Expand Up @@ -57,7 +56,6 @@ describe('LangGraph integration', () => {
createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument-with-pii.mjs', (createRunner, test) => {
test('should instrument LangGraph with genAI recording enabled', async () => {
await createRunner()
.ignore('event')
.expect({ transaction: { transaction: 'langgraph-test' } })
.expect({
span: container => {
Expand Down Expand Up @@ -93,7 +91,6 @@ describe('LangGraph integration', () => {
createEsmAndCjsTests(__dirname, 'scenario-tools.mjs', 'instrument-with-pii.mjs', (createRunner, test) => {
test('should capture tools from LangGraph agent', { timeout: 30000 }, async () => {
await createRunner()
.ignore('event')
.expect({ transaction: { transaction: 'langgraph-tools-test' } })
.expect({
span: container => {
Expand Down Expand Up @@ -139,7 +136,6 @@ describe('LangGraph integration', () => {
createEsmAndCjsTests(__dirname, 'scenario-thread-id.mjs', 'instrument.mjs', (createRunner, test) => {
test('should capture thread_id as gen_ai.conversation.id', async () => {
await createRunner()
.ignore('event')
.expect({ transaction: { transaction: 'langgraph-thread-id-test' } })
.expect({
span: container => {
Expand Down Expand Up @@ -180,7 +176,6 @@ describe('LangGraph integration', () => {
(createRunner, test) => {
test('extracts system instructions from messages', async () => {
await createRunner()
.ignore('event')
.expect({ transaction: { transaction: 'main' } })
.expect({
span: container => {
Expand All @@ -203,7 +198,6 @@ describe('LangGraph integration', () => {
createEsmAndCjsTests(__dirname, 'scenario-resume.mjs', 'instrument.mjs', (createRunner, test) => {
test('should not throw when invoke is called with null input (resume scenario)', async () => {
await createRunner()
.ignore('event')
.expect({
transaction: {
transaction: 'langgraph-resume-test',
Expand Down Expand Up @@ -238,7 +232,6 @@ describe('LangGraph integration', () => {
createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument-span-streaming.mjs', (createRunner, test) => {
test('creates langgraph related spans with span streaming enabled', async () => {
await createRunner()
.ignore('event')
.expect({
span: container => {
const weatherTodaySpan = container.items.find(span =>
Expand All @@ -265,7 +258,6 @@ describe('LangGraph integration', () => {
createEsmAndCjsTests(__dirname, 'agent-scenario.mjs', 'instrument-agent.mjs', (createRunner, test) => {
test('should instrument createReactAgent with agent and chat spans', { timeout: 30000 }, async () => {
await createRunner()
.ignore('event')
.expect({
transaction: event => {
const spans = event.spans ?? [];
Expand Down Expand Up @@ -308,7 +300,6 @@ describe('LangGraph integration', () => {
createEsmAndCjsTests(__dirname, 'agent-tools-scenario.mjs', 'instrument-agent.mjs', (createRunner, test) => {
test('should create tool execution spans for createReactAgent with tools', { timeout: 30000 }, async () => {
await createRunner()
.ignore('event')
.expect({
transaction: event => {
const spans = event.spans ?? [];
Expand Down Expand Up @@ -364,7 +355,6 @@ describe('LangGraph integration', () => {
createEsmAndCjsTests(__dirname, 'scenario-stategraph-chat.mjs', 'instrument-agent.mjs', (createRunner, test) => {
test('auto-injects langchain handler for plain StateGraph and emits chat spans', { timeout: 30000 }, async () => {
await createRunner()
.ignore('event')
.expect({
transaction: event => {
expect(event.transaction).toBe('main');
Expand Down
9 changes: 2 additions & 7 deletions packages/server-utils/src/ai/langgraph/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/* eslint-disable typescript-eslint/no-deprecated */
import {
captureException,
SEMANTIC_ATTRIBUTE_SENTRY_OP,
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
SPAN_STATUS_ERROR,
Expand Down Expand Up @@ -183,13 +182,9 @@ export function instrumentCompiledGraphInvoke(

return result;
} catch (error) {
// The error is rethrown to the caller (invoke() rejects), so we only mark the span failed
// and do not record it.
span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });
captureException(error, {
mechanism: {
handled: false,
type: 'auto.ai.langgraph.error',
},
});
throw error;
}
},
Expand Down
9 changes: 2 additions & 7 deletions packages/server-utils/src/ai/langgraph/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/* eslint-disable typescript-eslint/no-deprecated */
import {
captureException,
SEMANTIC_ATTRIBUTE_SENTRY_OP,
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
SPAN_STATUS_ERROR,
Expand Down Expand Up @@ -141,13 +140,9 @@ export function wrapToolsWithSpans(tools: unknown[], options: LangGraphOptions,

return result;
} catch (error) {
// The error is rethrown to the caller (invoke() rejects), so we only mark the span
// failed and do not record it.
span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });
captureException(error, {
mechanism: {
handled: false,
type: 'auto.ai.langgraph.error',
},
});
throw error;
}
},
Expand Down
Loading