Checked other resources
Related Issues / PRs
Reproduction Steps / Example Code (Python)
# pip install "langgraph==1.2.2" langgraph-checkpoint "openinference-instrumentation-langchain==0.1.67"
import logging
from typing import TypedDict
logging.basicConfig(level=logging.WARNING)
from openinference.instrumentation.langchain import LangChainInstrumentor
LangChainInstrumentor().instrument()
from langgraph.callbacks import GraphCallbackHandler, _GraphCallbackManager
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.graph import END, START, StateGraph
from langgraph.types import Command, interrupt
class State(TypedDict):
n: int
def node(state: State) -> State:
interrupt("gate")
return {"n": state["n"] + 1}
builder = StateGraph(State)
builder.add_node("node", node)
builder.add_edge(START, "node")
builder.add_edge("node", END)
graph = builder.compile(checkpointer=InMemorySaver())
config = {"configurable": {"thread_id": "1"}}
graph.invoke({"n": 0}, config) # pauses -> on_interrupt dispatch
graph.invoke(Command(resume="go"), config) # resumes -> on_resume dispatch
handlers = _GraphCallbackManager.configure(None, run_id=None).handlers
print("handlers in the graph lifecycle manager:", [type(h).__name__ for h in handlers])
print("all GraphCallbackHandler?", all(isinstance(h, GraphCallbackHandler) for h in handlers))
Error Message and Stack Trace (if applicable)
WARNING:langchain_core.callbacks.manager:Error in OpenInferenceTracer.on_interrupt callback: AttributeError("'OpenInferenceTracer' object has no attribute 'on_interrupt'")
WARNING:langchain_core.callbacks.manager:Error in OpenInferenceTracer.on_resume callback: AttributeError("'OpenInferenceTracer' object has no attribute 'on_resume'")
handlers in the graph lifecycle manager: ['OpenInferenceTracer']
all GraphCallbackHandler? False
Pinning openinference-instrumentation-langchain==0.1.70 (which added no-op on_interrupt/on_resume to its tracer purely to silence this) removes the two warnings but not the cause — the last two lines are unchanged:
handlers in the graph lifecycle manager: ['OpenInferenceTracer']
all GraphCallbackHandler? False
Description
_GraphCallbackManager / _AsyncGraphCallbackManager are documented to carry only GraphCallbackHandler instances, and every entry point (configure(), copy(), the cross-type constructors) runs _filter_graph_handlers to enforce that. But the filter runs on the constructor arguments, and _init_base_manager then calls BaseCallbackManager.__init__ — which is exactly where LangChain instrumentors monkey-patch to append their handler to every callback manager. So the injection lands after the filter, and the invariant the class documents is not true of the constructed object.
The consequence is that on_interrupt/on_resume dispatch through handle_event to a handler that never implements them, so every interrupt and every resume logs an AttributeError at WARNING. It's swallowed (raise_error is False), so it is noise rather than breakage — but it is per-interrupt and per-resume. In our production workload (human-in-the-loop agents, so every turn is gated) that was a few hundred lines/day across the Celery workers.
This is the sequel to #7543. That issue reported the hard-failure version of the same collision: in 1.1.7 the managers overrode add_handler to raise TypeError("handlers must inherit GraphCallbackHandler"), and the injected handler crashed graph invocation. In 1.2.2 that override is gone, so the injected handler is now accepted silently — the crash became a warning, but the handler still ends up in a manager that then dispatches graph lifecycle events to it.
Worth noting the failure isn't specific to one vendor or to the two callbacks that exist today. Any instrumentor that patches BaseCallbackManager.__init__ hits it (openinference and openllmetry both do), and each new graph lifecycle callback added to this API reopens it for every instrumentor that hasn't yet shipped a matching stub. The current state is that the ecosystem works around a LangGraph invariant by adding no-op methods for LangGraph-private events to unrelated tracers.
Suggested fix — re-apply the existing predicate where it can't be bypassed, either at the end of _init_base_manager:
BaseCallbackManager.__init__(manager, ...)
manager.handlers = _filter_graph_handlers(manager.handlers)
manager.inheritable_handlers = _filter_graph_handlers(manager.inheritable_handlers)
manager.run_id = run_id
or at the dispatch sites, if you'd rather leave the handler list untouched:
def on_interrupt(self, event: GraphInterruptEvent) -> None:
handle_event(_filter_graph_handlers(self.handlers), "on_interrupt", None, event)
Either restores what the class already documents. Happy to open a PR with tests if you'd like — just say which shape you prefer.
System Info
langgraph==1.2.2
langgraph-checkpoint==4.2.0
langchain-core==1.5.4
openinference-instrumentation-langchain==0.1.67 (and 0.1.70)
Python 3.13.14
macOS-26.5.2-arm64
Checked other resources
Related Issues / PRs
TypeErrorvariant of this same collision, withopentelemetry-instrumentation-langchainReproduction Steps / Example Code (Python)
Error Message and Stack Trace (if applicable)
Pinning
openinference-instrumentation-langchain==0.1.70(which added no-opon_interrupt/on_resumeto its tracer purely to silence this) removes the two warnings but not the cause — the last two lines are unchanged:Description
_GraphCallbackManager/_AsyncGraphCallbackManagerare documented to carry onlyGraphCallbackHandlerinstances, and every entry point (configure(),copy(), the cross-type constructors) runs_filter_graph_handlersto enforce that. But the filter runs on the constructor arguments, and_init_base_managerthen callsBaseCallbackManager.__init__— which is exactly where LangChain instrumentors monkey-patch to append their handler to every callback manager. So the injection lands after the filter, and the invariant the class documents is not true of the constructed object.The consequence is that
on_interrupt/on_resumedispatch throughhandle_eventto a handler that never implements them, so every interrupt and every resume logs anAttributeErrorat WARNING. It's swallowed (raise_erroris False), so it is noise rather than breakage — but it is per-interrupt and per-resume. In our production workload (human-in-the-loop agents, so every turn is gated) that was a few hundred lines/day across the Celery workers.This is the sequel to #7543. That issue reported the hard-failure version of the same collision: in 1.1.7 the managers overrode
add_handlertoraise TypeError("handlers must inherit GraphCallbackHandler"), and the injected handler crashed graph invocation. In 1.2.2 that override is gone, so the injected handler is now accepted silently — the crash became a warning, but the handler still ends up in a manager that then dispatches graph lifecycle events to it.Worth noting the failure isn't specific to one vendor or to the two callbacks that exist today. Any instrumentor that patches
BaseCallbackManager.__init__hits it (openinference and openllmetry both do), and each new graph lifecycle callback added to this API reopens it for every instrumentor that hasn't yet shipped a matching stub. The current state is that the ecosystem works around a LangGraph invariant by adding no-op methods for LangGraph-private events to unrelated tracers.Suggested fix — re-apply the existing predicate where it can't be bypassed, either at the end of
_init_base_manager:or at the dispatch sites, if you'd rather leave the handler list untouched:
Either restores what the class already documents. Happy to open a PR with tests if you'd like — just say which shape you prefer.
System Info