Agnost AIAgnost AIBook a demo
Open +
← All articles

LangGraph Observability: Monitor State, Interrupts, and Retries

A practical guide to LangGraph monitoring with Agnost: preserve thread identity, distinguish paused runs from failures, and diagnose loops and repeated actions.

A LangGraph agent may pause for approval, resume on another request, revisit a node, and eventually return an answer. Treating each HTTP response as a finished task loses the workflow. Treating the whole thread as one uninterrupted model call hides where the time went.

LangGraph observability needs both execution history and persistent workflow identity. Track each invocation as an attempt, preserve the conversation across resumes, and distinguish a completed answer from a graph waiting for input. Node traces then explain how the workflow reached that state.

Agnost AI records agent interactions through its SDK and ingests supported OpenTelemetry traces. Its LangChain/LangGraph integration provides the setup paths. A wrapper around graph.invoke() captures that boundary; it does not automatically expose every node, checkpoint, or state update.

LangGraph monitoring boundaries: User request → Graph attempt → Approval pause → Resume attempt → Action result
Monitoring model for LangGraph. One conversation; separate execution attempts and waiting time.

How to debug a LangGraph agent

For a graph compiled with a checkpointer, start with the affected thread. Inspect graph.get_state(config) and graph.get_state_history(config); history is returned newest first. Compare the last expected step with the first unexpected transition. The official checkpoint guide describes these inspection methods.

# Read-only inspection of your existing checkpointed graph.
config = {"configurable": {"thread_id": affected_thread_id}}
snapshot = graph.get_state(config)
print("Next nodes:", snapshot.next)
for checkpoint in graph.get_state_history(config):
    print(checkpoint.created_at, checkpoint.next)

Inspect approved state fields locally when you need more detail. Avoid printing the entire state into shared logs. Check whether the workflow is waiting for approval, has a failed task, or repeatedly routes to the same node. Replaying a checkpoint executes subsequent work again; review external side effects before using replay as a debugging shortcut.

Use this inspection to explain one execution. In Agnost, connect its recorded interaction to the user and conversation, then investigate whether the same failure recurs across requests. A conversation wrapper does not provide a checkpoint debugger.

Worked example: an approved action is performed twice

Imagine a LangGraph expense workflow that prepares a reimbursement, pauses for approval, and resumes when a reviewer responds. This is an illustrative design review, not a production incident report.

Evidence to record Example meaning Why it matters
Stable thread and conversation One reimbursement request Links both execution segments
First attempt ends paused Approval is outstanding Prevents a false failure classification
Resume starts a new attempt Reviewer supplied a decision Separates active execution from waiting
One business action ID The intended reimbursement Detects duplicate external effects
Payment system result Accepted, rejected, or pending Establishes the authoritative outcome

If two payment records exist for one action ID, inspect where the side effect sits relative to the interrupt and what code is re-entered on resume. A repeated node is not by itself proof of a duplicate payment; the external records are the deciding evidence.

If no payment exists but the final answer says “reimbursed,” compare the resumed tool result with the answer. The failure may be an unsupported completion claim rather than checkpointing.

Keep approval latency and compute latency separate in the review. A reviewer taking an afternoon to respond should not make the model appear slow. The product’s end-to-end time still includes that wait, so preserve both measurements.

Agnost conversation view with illustrative demo data
Product demo · illustrative data. The conversation panel lets you inspect what a user already supplied before the agent asks again. That is the starting evidence for a state or context-propagation investigation. Select the image to inspect it at full size.

Metrics that answer useful LangGraph questions

Use these definitions to design your measurement plan. Calculate them from the required application or tracing evidence; they are not all precomputed dashboard metrics.

Metric Definition Interpretation
Execution error rate Failed invocation attempts / recorded invocation attempts A deliberate interrupt is not an execution error.
Pending workflow age Now minus the time approval was requested Report still-pending workflows; do not drop them.
Confirmed completion Workflows with a confirmed terminal outcome / eligible workflows Keep the cohort and observation window explicit.

Keep thread, conversation, and attempt IDs separate

A thread is the persistent execution context used with LangGraph checkpointing. An invocation is an attempt to advance that context. A product conversation is the sequence the user understands as one interaction. These may share a stable identifier when your application has a one-to-one mapping, but they are different concepts.

Identifier Lifetime Why it matters
User ID Across the user’s activity Separates people and accounts
Conversation ID Related user turns Reconstructs the product experience
Thread ID Persistent graph state Continues the right workflow
Attempt ID One invocation or resume Distinguishes retries and execution segments
Action ID One external operation Reveals duplicate side effects

Generate a fresh attempt ID on each invocation. Keep a thread’s conversation ID stable. Never use a shared constant thread ID across users. If a thread is reused for a different customer, observability is not the only problem: state itself may be mixed.

LangGraph’s persistence documentation explains how thread_id addresses saved state. Its interrupt documentation explains pausing and resuming. Verify these behaviors against your installed version, especially if your application consumes streamed results rather than the default invocation output.

Instrument a graph invocation with Agnost

Install agnost in your existing Python application. The following adapter is for an already compiled state graph whose non-streaming result is a dictionary. It records execution segments, not a universal definition of graph completion.

Example scope: the code below is an integration adapter for an existing application. Configure its framework, model, credentials, and output contract as described; the demo screenshots were not generated by running these snippets.

pip install agnost
export AGNOST_ORG_ID="your-org-id"
import os
from uuid import uuid4
import agnost

agnost.init(os.environ["AGNOST_ORG_ID"])


def observed_invoke(graph, graph_input, *, safe_input,
                    user_id, conversation_id, thread_id,
                    output_to_text):
    interaction = agnost.begin(
        user_id=user_id,
        conversation_id=conversation_id,
        agent_name="langgraph-workflow",
        input=safe_input,
        properties={
            "framework": "langgraph",
            "thread_id": thread_id,
            "attempt_id": str(uuid4()),
            "graph_version": "workflow-v1",
        },
    )
    try:
        result = graph.invoke(
            graph_input,
            config={"configurable": {"thread_id": thread_id}},
        )
        paused = bool(result.get("__interrupt__"))
        # Select and redact your public output; don't serialize all graph state.
        output = "Waiting for input or approval" if paused else output_to_text(result)
    except Exception as exc:
        interaction.end(output=type(exc).__name__, success=False)
        raise
    else:
        interaction.set_property("execution_state", "paused" if paused else "returned")
        interaction.end(output=output, success=True)
        return result

Supply output_to_text from your application’s state contract—for example, a function selecting the final public answer. Do not dump checkpoint state: it may contain private documents, credentials, or intermediate data the user never saw. safe_input is your sanitized description of this invocation, including a resume when applicable.

The success flag here means invocation processing returned without an exception. A paused run is deliberately labeled paused, not resolved. If your graph uses another output shape or pause mechanism, adapt that detection before using the wrapper. Flush the Agnost SDK at process shutdown; do not shut it down between turns of a shared server.

Observe resumes without turning them into new users

When a person approves a pending action, reuse the graph thread and product conversation. Record a new invocation attempt for the resume. That lets you measure three different durations:

  1. Active execution before approval was requested.
  2. Wall-clock time waiting for the human.
  3. Active execution after approval.

A two-hour approval wait should not appear as two hours of model latency. It may still matter to the user’s end-to-end completion time. Present both durations under accurate names.

An approval also does not prove that the requested action happened. For a refund workflow, record the payment system’s outcome after the approved call. The agent’s statement “refund issued” is weaker evidence than the transaction result.

Add node traces to explain loops and retries

Use the Agnost integration’s OpenTelemetry configuration when you need execution detail beyond the wrapper. Configure the tracing stack once at startup and preserve your existing provider if you already have one. Inspect an actual exported trace to establish which node, tool, and model operations are captured.

Then compare repeated nodes against state changes. A repeated retrieval node may be useful if it changes the query after weak evidence. Repeating the same retrieval with the same input and no new information points to a different problem. Record a compact state transition summary, such as the routing decision or retrieved document IDs, rather than every state field.

Retries need their own attempt context. A transient API failure followed by a successful retry differs from a graph that reaches its recursion limit. Look for the earliest failed dependency and whether later steps recovered. Reporting only the last error can obscure the original cause.

Make side effects safe to interpret

LangGraph can re-enter node code during resumed execution. Review the framework’s interrupt semantics before placing external actions around a pause. Observability can reveal duplicate sends or writes, but cannot make an operation idempotent.

For an illustrative approval workflow, use evidence like this:

Recorded event Interpretation
Draft created The agent prepared an action
Approval requested Workflow paused intentionally
Approval received Human authorized continuation
Delivery API accepted request External system accepted the operation
Delivery confirmed Product’s delivery criterion was met

These are application events to define and instrument, not automatic Agnost fields. Reuse the same action identifier through retries so you can distinguish one action attempted twice from two intended actions.

What to review in production

In Agnost, inspect a conversation in Users, then examine the related Events. Start with a concrete question: are users abandoning a particular approval step, are certain routes repeatedly revisiting a node, or did a graph revision increase failures for one intent?

Keep these denominators distinct:

  • Failed invocation attempts divided by invocation attempts.
  • Completed workflows divided by workflows with an observed terminal state.
  • Pending workflows grouped by age.

Show pending and unknown states alongside completion. Excluding them silently can make a system with stuck workflows look healthy. If you sample traces, report that limitation before interpreting rare loops as absent.

Common instrumentation mistakes

Every turn is a separate conversation. Check that your conversation mapping survives request boundaries, rather than creating a new ID inside the wrapper.

One graph has implausibly long latency. Separate active execution from time between invocations and approval waits.

Everything is successful despite pending approvals. Inspect the recorded execution state. A returned call is not necessarily a terminal graph result.

Traces appear twice. Check whether multiple instrumentors or exporters are producing duplicate spans. Keep request-level SDK events separate from node-level spans in metrics.

The trace does not explain a wrong answer. Add the smallest useful evidence at the decision boundary: route selected, validation result, or document references. More raw state does not necessarily make diagnosis easier.

Frequently asked questions

Can I monitor LangGraph without changing every node?

Yes. Start at the invocation boundary and add framework tracing. Add custom spans only where the existing trace cannot explain an important decision or external action.

Is LangGraph monitoring the same as LangChain monitoring?

They share tooling, but persistent graph execution adds concerns such as resumes, checkpoints, and repeated node execution. For a simpler request-to-response agent, start with the LangChain monitoring guide.

Browse all agent observability guides by framework.