From 629d27c8ce720ee243130f869522218e1a26ce48 Mon Sep 17 00:00:00 2001 From: Wahaj Ahmed Date: Wed, 3 Jun 2026 15:47:28 +0200 Subject: [PATCH] fix(langchain): filter GraphBubbleUp control-flow exceptions in _handle_error LangGraph raises GraphBubbleUp/GraphInterrupt for normal control flow (human-in-the-loop interrupts via langgraph.types.interrupt()). Sentry's SentryLangchainCallback was capturing these as errors via on_tool_error, creating false-positive issues. Add a lazy module-level import of GraphBubbleUp from langgraph.errors, and skip _handle_error for isinstance checks against this type. Fixes: getsentry/sentry-python#6384 Co-authored-by: AI assistant (OpenClaw Buck) --- sentry_sdk/integrations/langchain.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sentry_sdk/integrations/langchain.py b/sentry_sdk/integrations/langchain.py index 054a953a01..ec67b33c60 100644 --- a/sentry_sdk/integrations/langchain.py +++ b/sentry_sdk/integrations/langchain.py @@ -117,6 +117,16 @@ except ImportError: OllamaEmbeddings = None +# LangGraph raises GraphBubbleUp / GraphInterrupt for normal control flow +# (human-in-the-loop interrupts, etc.) — these should never be captured as errors. +_graph_bubble_up: "type | tuple[()]" = () +try: + from langgraph.errors import GraphBubbleUp # type: ignore[import-untyped] + + _graph_bubble_up = GraphBubbleUp +except ImportError: + pass + def _get_ai_system(all_params: "Dict[str, Any]") -> "Optional[str]": ai_type = all_params.get("_type") @@ -266,6 +276,12 @@ def _handle_error(self, run_id: "UUID", error: "Any") -> None: if not run_id or run_id not in self.span_map: return + # LangGraph raises GraphBubbleUp/GraphInterrupt for normal + # control flow (e.g. human-in-the-loop interrupts). These are + # not errors and should not be captured as Sentry issues. + if isinstance(error, _graph_bubble_up): + return + span = self.span_map[run_id] sentry_sdk.capture_exception(