Skip to content

on_tool_error, on_retriever_error, and on_llm_error missing CONTROL_FLOW_EXCEPTION_TYPES check in Langchain callback handler #1515

@vishnumishra

Description

@vishnumishra

Bug

LangGraph uses exceptions inheriting from GraphBubbleUp for control flow — not actual errors:

GraphBubbleUp (base)
├── GraphInterrupt    — raised by interrupt() for human-in-the-loop
│   └── NodeInterrupt — deprecated, same purpose
└── ParentCommand     — raised by Command() for agent handoffs

The Langchain callback handler already defines CONTROL_FLOW_EXCEPTION_TYPES (line 84) and populates it with GraphBubbleUp (line 89) to filter these out. on_chain_error uses this check correctly (line 583), but three other error handlers do not:

Handler Line Has check?
on_chain_error 572 Yes
on_tool_error 796 No
on_retriever_error 245 No
on_llm_error 990 No

The most impactful is on_tool_error, since LangGraph tools are the primary place where interrupt() and Command() are called.

Impact

Any LangGraph tool that uses interrupt() (human-in-the-loop) or returns a Command() (agent handoff) is incorrectly marked as a red ERROR in Langfuse traces. This pollutes dashboards and makes it impossible to distinguish real tool failures from normal control flow.

Expected behavior

Control-flow exceptions should be recorded with level="DEFAULT" and preserve the status message so users can see why the run stopped, without being flagged as an error.

Suggested fix

Apply the same CONTROL_FLOW_EXCEPTION_TYPES guard to all three handlers, using level="DEFAULT" (instead of None as on_chain_error currently does) to preserve visibility:

if any(isinstance(error, t) for t in CONTROL_FLOW_EXCEPTION_TYPES):
    level = "DEFAULT"
else:
    level = "ERROR"

observation.update(
    level=cast(Optional[Literal["DEBUG", "DEFAULT", "WARNING", "ERROR"]], level),
    status_message=str(error),
    ...
)

The same improvement should also be applied to on_chain_error for consistency — its current level=None / status_message=None behavior makes control-flow interruptions invisible in traces.

Related issues

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions