Skip to content

LangchainIntegration reports GraphInterrupt / GraphBubbleUp as errors via on_tool_error #6384

@pyarun

Description

@pyarun

Environment

  • sentry-sdk 2.59.0 (also confirmed present on master / 2.60.0)
  • langchain-core 1.x, langgraph 0.x
  • LangChain integration auto-enabled (not explicitly added)

Problem

When langgraph.types.interrupt() is called from inside a LangChain StructuredTool — the standard pattern for exposing human-in-the-loop pauses as agent tools (e.g. deepagents) — it raises GraphInterrupt, a subclass of langgraph.errors.GraphBubbleUp. This is normal control flow, not an error: LangGraph's pregel executor catches it upstream and checkpoints the graph.

However:

  1. langchain_core's BaseTool.arun does not special-case GraphBubbleUp. It catches it in the generic except (Exception, KeyboardInterrupt) and calls run_manager.on_tool_error(error) before re-raising.
  2. Sentry's SentryLangchainCallback.on_tool_error -> _handle_error calls sentry_sdk.capture_exception(error, ...) with no exception-type filtering:
def _handle_error(self, run_id, error):
    with capture_internal_exceptions():
        if not run_id or run_id not in self.span_map:
            return
        span_data = self.span_map[run_id]
        span = span_data.span
        sentry_sdk.capture_exception(error, span.scope)   # captures GraphInterrupt as an error
        ...

Result: every trace-sampled HITL interrupt becomes a false-positive error issue in Sentry. (Note the dedicated LanggraphIntegration is tracing-only and does not have this problem — only the LangChain integration does.)

Expected

GraphBubbleUp exceptions (GraphInterrupt, etc.) are LangGraph control-flow signals and should not be captured as errors. _handle_error (or on_tool_error) should skip them:

try:
    from langgraph.errors import GraphBubbleUp
except ImportError:
    GraphBubbleUp = ()

def _handle_error(self, run_id, error):
    if isinstance(error, GraphBubbleUp):
        return  # langgraph control flow, not an error
    ...

Workaround

Consumers can pass ignore_errors=[GraphBubbleUp] to sentry_sdk.init(), but the integration shipping a correct default would be preferable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No fields configured for issues without a type.

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions