From c6f21eed74a809a112e12749e5001cf0eb6e3dc6 Mon Sep 17 00:00:00 2001 From: Nicolas Hrubec Date: Wed, 26 Aug 2026 11:36:39 +0200 Subject: [PATCH] fix(v10/core): Don't capture caller-handled LangGraph errors Backport of: #23594 --- .../suites/tracing/langgraph/test.ts | 9 --------- packages/core/src/tracing/langgraph/index.ts | 17 ++++------------- packages/core/src/tracing/langgraph/utils.ts | 9 ++------- 3 files changed, 6 insertions(+), 29 deletions(-) diff --git a/dev-packages/node-integration-tests/suites/tracing/langgraph/test.ts b/dev-packages/node-integration-tests/suites/tracing/langgraph/test.ts index 817aef2923ca..944e5bdc05a4 100644 --- a/dev-packages/node-integration-tests/suites/tracing/langgraph/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/langgraph/test.ts @@ -28,7 +28,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') .expect({ transaction: { transaction: 'langgraph-test' } }) .expect({ span: container => { @@ -67,7 +66,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 => { @@ -107,7 +105,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 => { @@ -173,7 +170,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 => { @@ -219,7 +215,6 @@ describe('LangGraph integration', () => { (createRunner, test) => { test('extracts system instructions from messages', async () => { await createRunner() - .ignore('event') .expect({ transaction: { transaction: 'main' } }) .expect({ span: container => { @@ -242,7 +237,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', @@ -372,7 +366,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 ?? []; @@ -411,7 +404,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 ?? []; @@ -463,7 +455,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 => { const spans = event.spans ?? []; diff --git a/packages/core/src/tracing/langgraph/index.ts b/packages/core/src/tracing/langgraph/index.ts index 7a78e952758a..eaaa9543ea97 100644 --- a/packages/core/src/tracing/langgraph/index.ts +++ b/packages/core/src/tracing/langgraph/index.ts @@ -1,4 +1,3 @@ -import { captureException } from '../../exports'; import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../../semanticAttributes'; import { SPAN_STATUS_ERROR } from '../../tracing'; import { @@ -119,13 +118,9 @@ export function instrumentStateGraphCompile( return compiledGraph; } catch (error) { + // The error is rethrown to the caller (compile() throws), 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; } }); @@ -242,13 +237,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; } }, diff --git a/packages/core/src/tracing/langgraph/utils.ts b/packages/core/src/tracing/langgraph/utils.ts index cf37ce18056e..d48683b52ac8 100644 --- a/packages/core/src/tracing/langgraph/utils.ts +++ b/packages/core/src/tracing/langgraph/utils.ts @@ -1,4 +1,3 @@ -import { captureException } from '../../exports'; import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../../semanticAttributes'; import { SPAN_STATUS_ERROR } from '../../tracing'; import type { Span, SpanAttributes } from '../../types/span'; @@ -140,13 +139,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; } },