LangGraph blueprint · Customer support
Debugging an agent with time travel
Pulls a misbehaving support-agent thread from its checkpointer, inspects the state history, replays from an earlier checkpoint and forks it with update_state to test a different tool result, then compares outcomes to find and lock in a fix. It must never let a replay or fork trigger real side effects, such as refunds or customer emails, against production systems.
- Steps
- 8
- Subjective questions
- 33
- Objective questions
- 33
The problem and the outcome
Problem: A LangGraph support agent gave a customer a wrong answer, and nobody can tell whether the cause was the model, the prompt or a bad tool result. Re-running the whole conversation from scratch does not reproduce the exact state the agent was in.
Outcome: Engineers can step back to the exact super-step where things went wrong, change one input and watch the agent's alternative path. Root causes are isolated quickly, and every fixed failure becomes a regression case.
Architecture
How it works, step by step
- The engineer opens the failing conversation in LangSmith, notes its thread_id and points a debug copy of the graph at the same checkpointer. In that copy, side-effecting tools such as refunds and emails are swapped for sandboxed versions.
- Call graph.get_state_history({"configurable": {"thread_id": tid}}) to list StateSnapshots, newest first. For each snapshot, inspect values, next, tasks and metadata (step, source, writes) to see what every super-step changed.
- Pick the snapshot whose next is ('tools',), where the last AIMessage holds the tool call that returned bad data. Keep its config, which carries the checkpoint_id.
- Replay by calling graph.invoke(None, snapshot.config). Steps before the checkpoint are not re-executed; nodes after it run again, which shows whether the failure reproduces or was caused by model nondeterminism.
- Fork by calling graph.update_state(snapshot.config, {"messages": [ToolMessage(content=corrected, tool_call_id=call_id)]}, as_node="tools"). This writes a new checkpoint on a branch and leaves the original history untouched.
- Resume the fork with graph.stream(None, fork_config, stream_mode="updates"). The graph continues from the edges after the tools node, so the agent reasons over the substituted tool result.
- Compare the final states of the original run, the replay and the fork: the messages, the tool calls chosen and the final reply. If the fork behaves correctly, the tool result was the cause; if it still fails, the prompt or model logic is at fault.
- Apply the fix, which may be tool output validation, a schema change or a prompt change. Add the checkpointed input as a LangSmith dataset example and re-run it to confirm the fix before shipping.
Tech stack
- LangGraph StateGraph with add_messages reducer
- PostgresSaver (langgraph-checkpoint-postgres) in production
- InMemorySaver for local reproduction tests
- LangSmith tracing and datasets
- LangGraph Studio for visual history and forking
- Python with pytest for regression runs
Key design decisions
- Debug against a separate graph instance with sandboxed tools rather than the production deployment, because re-executed nodes call tools again.
- Fork with update_state(..., as_node="tools") at the checkpoint before the tools node, so the fake result is routed exactly as a real tool output would be.
- Keep replay and fork as separate runs, so model nondeterminism (seen in replay) is not confused with tool-result effects (seen in fork).
- Use the checkpointer as the source of truth for state and LangSmith traces for model inputs and outputs; together they explain both what the state was and why the model acted.
- Convert every confirmed time-travel diagnosis into a dataset example so the same failure is caught before release.
Common mistakes
- Passing a real input instead of None to invoke with a checkpoint config starts new input processing, not a resume from that checkpoint.
- Omitting as_node in update_state makes LangGraph infer which node wrote the update, which can route the fork to the wrong next step.
- Forgetting the add_messages reducer: a new ToolMessage is appended unless its id matches an existing message, so a careless update can leave both the bad and corrected results in state.
- Replaying with production tool credentials re-sends refunds, emails or ticket updates for every node after the checkpoint.
- Treating one replay as proof: a nondeterministic model can pass once by chance, so repeat the run or pin the model settings before drawing conclusions.
What to measure
- Time from bug report to confirmed root cause per incident
- Share of agent incidents reproduced through replay from checkpoints
- Regression dataset pass rate before each release
- Count of repeat incidents with an already-fixed root cause
- Accidental side effects triggered during debugging (target zero)
Most-asked interview questions
Subjective questions 33
1Walk me through how you would debug a LangGraph support agent that gave a customer a wrong refund answer.Asked almost every time
First I get the thread_id from the LangSmith trace and call get_state_history on a debug copy of the graph that uses the same Postgres checkpointer but sandboxed tools. I read the snapshots newest first, looking at values, next and the metadata writes, and I find the checkpoint just before the tools node ran the order lookup. I replay from there with invoke(None, config) to see whether the failure reproduces. Then I fork with update_state, passing a corrected ToolMessage as_node tools, and resume. If the fork answers correctly, the bad tool data was the cause, so I add validation on the tool. If it still fails, the prompt or the model is at fault. Either way, I add the case to a regression dataset.
Sourced from Docs by LangChain (MCP)
2Which fields of a StateSnapshot do you inspect while debugging, and what does each tell you?Asked almost every time
I look at five things. values is the full state at that checkpoint, mainly the messages list, so I can see exactly what the model had in front of it. next shows which nodes run next. A tuple like ('tools',) means a tool call is pending. tasks lists those pending tasks and any errors or interrupts attached to them. metadata carries step, source and writes. step tells me the super-step number, source tells me whether the checkpoint came from input, the normal loop or a manual update, and writes shows what each node changed. config holds the checkpoint_id I need to replay or fork from that point. Read newest to oldest, these fields let me reconstruct the run super-step by super-step.
Sourced from Docs by LangChain (MCP)
3How do you pick the exact checkpoint to fork from when a tool returned bad data?Asked almost every time
I walk the history from newest to oldest and find the snapshot where next is ('tools',) and the last AIMessage contains the tool call that later produced the bad result. This is the point after the model decided to call the tool and before the tools node ran. I note the tool call's id and arguments, and I keep snapshot.config, because it carries the thread_id and checkpoint_id. Forking here lets me inject a corrected ToolMessage as if the tools node had produced it. If the model called several tools in that turn, I confirm which call is the faulty one, because the ToolMessage I write has to match that tool_call_id.
Sourced from Docs by LangChain (MCP)
4How do you build the debug copy of the graph so that tools are sandboxed but the graph structure matches production?Asked almost every time
I compile the same graph definition, with the same nodes, edges, state schema and reducers, but I inject different tool implementations. Refund, email and ticket-update tools are replaced with stubs that log the call and return realistic fake responses. Read-only lookups can point at a staging or recorded copy of the data. The cleanest approach is dependency injection: the graph builder takes a tool registry, so production and debug differ only in that one argument. If the structure stayed identical but tool names changed, the AIMessage tool calls would not route correctly. I also give the debug process no production credentials, so even a missed tool swap cannot reach the real refund or email APIs.
Sourced from Docs by LangChain (MCP)
5How do you lock in the fix so the same bug does not come back?Asked almost every time
I turn the failing case into a regression test. I take the checkpointed input, meaning the conversation and relevant state up to the failure, and add it as an example in a LangSmith dataset, with the expected behaviour as the reference. That might be the correct refund policy answer or a refusal to issue a refund. I attach an evaluator that checks the right tool calls and the right reply. Then I apply the fix, whether that is tool output validation, a schema change or a prompt change, and run the dataset against the new version. I ship only when this example passes and the rest of the dataset does not regress. The example stays in the suite for future prompt and model changes.
Sourced from Docs by LangChain (MCP)
6What is the difference between replaying and forking in LangGraph time travel, and when do you use each?Very often asked
Replaying means invoking with None and a past checkpoint's config. LangGraph skips the steps already recorded before that checkpoint and re-executes everything after it. I use replay to check reproducibility: does the same state lead to the same bad outcome, or was it model randomness? Forking means calling update_state on a past checkpoint, which writes a new checkpoint on a branch with modified values, and then resuming from that branch. I use a fork to test a hypothesis, such as 'if the tool had returned the correct order status, would the agent have answered well?' The original history stays intact, so I can compare both branches side by side. Replay isolates nondeterminism, while a fork isolates a single cause.
Sourced from Docs by LangChain (MCP)
7How do you make time-travel debugging safe when the agent's tools have real side effects?Very often asked
The key fact is that every node after the chosen checkpoint runs again, including tool calls. So I never replay against the production deployment. I build a debug instance of the same StateGraph that reads the production checkpoints, or a copy of them, but binds sandboxed tools: refund and email tools are swapped for fakes that log the call and return canned responses. Read-only tools can hit staging. For forks, I often inject the tool result with update_state as_node tools, so the real tool is never called for that step. I also make production tools idempotent with request keys, so an accidental replay cannot double-refund a customer. Finally, I track accidental side effects during debugging as a metric, with a target of zero.
Sourced from Docs by LangChain (MCP)
8How do you tell whether the failure was deterministic or caused by model nondeterminism?Very often asked
I replay from the chosen checkpoint with graph.invoke(None, snapshot.config) several times. Steps before the checkpoint are not re-executed, but the model and tool nodes after it run again. If the same wrong refund answer comes back every time with the same inputs, the failure is effectively deterministic for that state, and I look at the prompt, the tool data or the routing logic. If some replays succeed and others fail, sampling variance is part of the cause. Then I consider a lower temperature, structured output, stronger instructions or a validation step. I record each replay's tool calls and final reply, so the comparison rests on evidence rather than a single rerun.
Sourced from Docs by LangChain (MCP)
9Why must the substituted ToolMessage carry the original tool_call_id?Very often asked
Chat models expect every tool call in an AIMessage to be answered by a ToolMessage with the matching tool_call_id. If the ids do not match, most providers reject the next request, or the model sees an unanswered call and a stray result it cannot link to anything. The match is also what makes the fork a faithful experiment. I want the only difference from the original run to be the content of that tool result, with the model's decision left exactly as it was. So I read the id from the last AIMessage's tool_calls in the snapshot and reuse it. If there were parallel calls, I supply a ToolMessage for each pending id, not just the one I am testing.
Sourced from Docs by LangChain (MCP)
10How do reducers on the state affect what update_state actually does?Very often asked
update_state does not overwrite state blindly. It applies the values I pass through the same reducers the nodes use. If messages has an append-style reducer, passing a list with one ToolMessage appends it to the existing messages instead of replacing the whole list. With LangChain's add_messages reducer, a message whose id matches an existing one replaces that message, which is useful if I fork after the tools node and want to swap an existing result. Keys without a reducer are overwritten. So before forking I check the state schema. Otherwise I might duplicate messages, wipe history or leave an extra key that changes routing.
Sourced from Docs by LangChain (MCP)
11Replays and forks write new checkpoints into the same thread. What risk does that create for production, and how do you manage it?Very often asked
The original checkpoints stay untouched, but the thread now has newer checkpoints on a branch. A plain get_state or invoke on that thread_id without a checkpoint_id resolves to the latest checkpoint. If the customer writes again and production resumes the thread, it could continue from my debug fork. To manage this, I prefer to copy the relevant checkpoints into a separate debug thread_id or a separate debug database and experiment there. If I have to work on the original thread, I do it only after the conversation is closed and restricted, and I record which checkpoint is the true production head. Either way, debug writes should never become the state a real customer continues from.
Sourced from Docs by LangChain (MCP)
12How do you compare the original run, the replay and the fork in a way that leads to a real conclusion?Very often asked
I put the final states side by side on three dimensions: the message sequence, the tool calls the agent chose with their arguments, and the final reply to the customer. Then I read the result as a small experiment. If the replay reproduces the bug and the fork with the corrected tool result fixes it, the tool data was the cause. If the fork still fails, the model reasoning or the prompt is at fault, even with good data. If the replay does not reproduce, nondeterminism played a part. LangSmith traces for each run help me see token-level reasoning and node metadata. I write down the conclusion before I change any code, so the fix targets the actual cause.
Sourced from Docs by LangChain (MCP)
13Checkpoints contain customer conversations and possibly PII. How do you handle privacy when debugging production threads?Very often asked
I treat the production checkpointer as sensitive data. Access goes through role-based permissions, and every read of a thread, plus every replay or fork, is logged for audit. Where possible, I copy the thread into a restricted debug environment with sensitive fields such as card details, addresses and phone numbers masked or tokenised, and I avoid downloading raw state to laptops. When I add the case to a LangSmith dataset, I redact or synthesise the PII so the regression example keeps the behaviour without the personal data. Retention policies apply to debug threads too, so they are deleted when the investigation ends. Since a model provider may see replayed prompts, I follow the same data agreements that govern production calls.
Sourced from Docs by LangChain (MCP)
14Why use a Postgres checkpointer in production instead of InMemorySaver for this kind of debugging?Very often asked
InMemorySaver lives in process memory, so checkpoints disappear on restart and are not shared between server instances. That is fine for local development but useless for investigating a customer complaint that arrived hours later. A Postgres checkpointer persists every super-step durably, survives restarts and deployments, and can be read by a separate debug process pointing at the same database or a restored copy. It also supports durable execution in production, so a crashed run resumes from its last checkpoint. For debugging, durability is the whole point. The exact state the agent had when it misbehaved is still there to inspect, replay and fork.
Sourced from Docs by LangChain (MCP)
15Beyond sandboxed tools, what defence in depth would you add so a debug run can never issue a real refund?Very often asked
I would add several independent layers. First, the debug environment gets no production credentials and no network route to payment or email services, so even a misconfigured tool fails closed. Second, production side-effect APIs require idempotency keys tied to the original tool call, so a replay that reached them would be deduplicated rather than charged twice. Third, refunds go through an interrupt for human approval. Fourth, tools check an explicit environment flag and refuse to run outside production. Fifth, alerts fire on any side-effect call that originates from a non-production service identity. Any one layer can fail, but all of them together make an accidental refund very unlikely.
Sourced from Docs by LangChain (MCP)
16If the fix is a prompt change, how do you make sure it does not break other conversations?Very often asked
Prompt changes have wide effects, so one passing example is not enough. I add the failing case to the LangSmith dataset and run the whole dataset of support scenarios against both the old and new prompt, comparing evaluator scores and looking at the cases that flipped. I also replay a few other historical threads from relevant checkpoints in the sandboxed debug graph to see real behaviour under the new prompt. Because model output varies, I run important examples more than once. If quality holds or improves and the target bug is fixed, I ship behind a gradual rollout and watch production traces for refund-related errors.
Sourced from Docs by LangChain (MCP)
17What do you do if the replay does not reproduce the failure?Very often asked
First I confirm the replay is faithful. Is it the same graph version, the same prompt, the same model and the same checkpoint? The production failure may have happened under an older deployment, so I check the version recorded in the trace. Next, I consider external state. Tool data may have changed since then, for example an order that has since been updated, so a live lookup now returns correct data. Recorded or snapshotted tool responses help here. If everything matches and the failure still does not reproduce, nondeterminism is likely, so I replay several times to estimate how often it fails. An intermittent failure still needs a fix, such as validation, structured output or clearer instructions, verified across repeated runs.
Sourced from Docs by LangChain (MCP)
18How does a fork stay isolated from the original execution history?Often asked
Checkpoints form a tree, not a list that gets edited in place. Each checkpoint has its own checkpoint_id and a parent_config that points to the checkpoint it came from. When I call update_state on an older snapshot's config, LangGraph writes a new checkpoint whose parent is that snapshot, and it returns a config pointing to the new one. The original children of that snapshot are still stored and still reachable by their ids. So I can always go back to the exact original run, compare it with the fork, or fork again with a different tool result. Nothing is lost, which makes the comparison trustworthy.
Sourced from Docs by LangChain (MCP)
19What does the source field in snapshot metadata tell you during debugging?Often asked
source tells me how a checkpoint was created. An input checkpoint holds the initial input before any node ran. Loop checkpoints come from normal execution, one per super-step. Update checkpoints come from update_state calls, meaning a person or tool edited the state manually. While debugging, this separates organic agent behaviour from edits. For example, if a production thread already contains an update checkpoint, a human may have patched state earlier, and that changes how I read the history. In my own fork, the update checkpoint marks exactly where I injected the corrected ToolMessage. Combined with step and writes, source lets me explain every transition in the thread.
Sourced from Docs by LangChain (MCP)
20Which streaming mode do you use while resuming a fork, and why?Often asked
I usually use stream_mode="updates", because it emits each node's state delta as it runs. I can watch the agent node receive the substituted ToolMessage and see exactly which new tool calls or reply it produces. values emits the full state after each step, which is noisier for long message lists but handy for a final check. messages streams LLM tokens with node metadata, which helps when I want to see the reasoning as it forms. debug gives the most detail, including checkpoint and task events, and is useful when routing itself is in question. Several modes can be combined in one stream call if needed.
Sourced from Docs by LangChain (MCP)
21How would you debug the failure if it happened inside a subgraph, such as a refunds sub-agent?Often asked
A subgraph compiled as a node shares the parent's checkpointer, so its state is persisted too. With get_state(config, subgraphs=True) I can see pending subgraph state at a parent checkpoint, and the subgraph's own checkpoints are namespaced under the parent thread. I first find the parent checkpoint where the subgraph node is next or in progress. Then I inspect the subgraph's internal history to locate the bad tool call. Forking then depends on where the fault is. I can update the subgraph's state at its own checkpoint, or update the parent state with the subgraph's output as_node set to the subgraph node. The sandboxing rule still applies: the subgraph's tools must be stubs in the debug copy.
Sourced from Docs by LangChain (MCP)
22What happens during replay or fork if a node calls interrupt(), for example a human approval step before refunds?Often asked
interrupt() pauses the node and saves a checkpoint with the pending interrupt. Replaying past that node pauses it again, and I continue by invoking with Command(resume=...) and a chosen value. This is useful for debugging because I can simulate an approver saying yes or no and see how the agent behaves in each case. It also means the approval gate is a natural safety layer. Even in production, refunds should sit behind an interrupt so a human confirms them. In debug, I still do not rely on the gate alone. The refund tool itself is sandboxed, so resuming with approval cannot move real money.
Sourced from Docs by LangChain (MCP)
23How do you reason about checkpoint storage growth when every thread is checkpointed at every super-step?Often asked
The number of checkpoints per thread grows roughly with the number of super-steps, and each one holds state, usually dominated by the messages list. Total storage is roughly threads × super-steps per thread × state size, plus pending writes. I would size it from our own measured averages rather than guess. Long support threads with big tool payloads are the main cost. Mitigations include keeping large blobs such as documents out of state and storing references instead, trimming or summarising messages, and setting a retention policy that prunes old threads. Time travel only needs history for threads we might investigate, so retention can be shorter for resolved, low-risk conversations.
Sourced from Docs by LangChain (MCP)
24How do parallel tool calls or Send fan-out change how you pick and fork a checkpoint?Often asked
When the model requests several tools in one turn, or a conditional edge returns Send objects, those tasks run in the same super-step, and the checkpoint before it lists several pending tasks. LangGraph also stores pending writes, so tasks that succeeded are not re-run if a sibling failed. To fork, I have to supply results for every pending call, each with its own tool_call_id, and change only the one I am testing. Otherwise the model sees unanswered calls. With Send, each branch has per-item state, and the reducer merges results. I check that my update merges the same way, for example appending with operator.add, so the fork matches what a real run would produce.
Sourced from Docs by LangChain (MCP)
25How would tool output validation prevent this class of bug?Often asked
If a bad tool result caused the wrong refund answer, the fix belongs at the boundary where data enters the agent. I would define a schema for the tool's response, covering things like order status, amount, currency and eligibility, and validate it before returning a ToolMessage. Invalid or inconsistent data, such as a refund amount above the order total, becomes a clear error message, so the model is told the lookup failed instead of reasoning over garbage. Optionally the agent then retries or escalates to a human. The fork experiment tells me which fields were wrong, so the validation targets real failure modes. I also add the bad payload as a unit test for the validator.
Sourced from Docs by LangChain (MCP)
26Why fork with update_state rather than editing the tool code to return the corrected data and rerunning the whole conversation?Often asked
Rerunning from the start changes many variables at once. Every earlier model call runs again and may decide differently, so I can no longer attribute the outcome to the tool result. Forking keeps everything before the checkpoint exactly as it happened, including the model's original tool call, and changes only one input. It is also cheaper, because only the nodes after the checkpoint run. Mocking in code still has a place. Once the cause is known, I write a deterministic test with a mocked tool. For diagnosis, though, a fork is the controlled experiment, and a full rerun is closer to a new sample.
Sourced from Docs by LangChain (MCP)
27Who should be allowed to run time-travel operations on production threads, and how do you govern it?Often asked
Reading history is less risky than writing to it, so I split permissions. A small group of on-call or support engineers can read production thread state for investigations, with each access logged and linked to a ticket. Writing, meaning update_state or running from a checkpoint, happens only in the debug environment against copied threads, never against the live production thread. Service identities for the debug process have no side-effect credentials. Audits record who inspected which thread_id and why, which matters for customer data protection. That way time travel stays a debugging tool and does not become a way to quietly alter customer records.
Sourced from Docs by LangChain (MCP)
28Do Store writes for long-term memory get rolled back by time travel, and what does that mean for debugging?Often asked
No. The Store, such as PostgresStore, holds long-term memory across threads in namespaces. It is separate from the checkpointer, so forking or replaying a thread does not undo Store writes. If a node saves a memory like 'customer prefers refunds to card', a replay would write it again, and a fork could write something wrong that later threads then read. So in the debug copy I give the graph a separate store, for example an InMemoryStore seeded with a copy of the relevant namespace, rather than the production store. I also check whether bad memory read from the Store caused the original failure, because that would not show up as a bad tool result.
Sourced from Docs by LangChain (MCP)
29Could you fork from the checkpoint after the tools node ran instead of before it, and how would that differ?Often asked
Yes. At that checkpoint next is typically the agent node, and the bad ToolMessage is already in messages. To fork there, I update state with a ToolMessage that has the same message id as the bad one, so add_messages replaces it instead of appending. I pass as_node="tools" so routing continues as if the tool had produced it. The result is equivalent, but there is more room for error: if I get the id wrong I end up with two results for one call. Forking before the tools node, where next is ('tools',), is simpler because I just supply the missing result. I choose based on which is clearer and verify the merged messages before resuming.
Sourced from Docs by LangChain (MCP)
30How would you debug a wrong handoff in a supervisor or swarm setup that uses Command(goto=..., update=...)?Sometimes asked
In these patterns, nodes route themselves by returning Command objects, so a wrong answer may come from handing off to the wrong agent rather than from bad tool data. In the state history, I look at metadata writes and next around the handoff step to see which node issued the Command, where it routed and what update it applied. To test an alternative, I fork at the checkpoint before the routing decision. I either update state so the supervisor sees different context, or apply an update as the supervisor node so the edges continue to the correct specialist. Then I compare outcomes. If the routing was the fault, the fix is usually clearer handoff tool descriptions or supervisor instructions.
Sourced from Docs by LangChain (MCP)
31If the agent is deployed on LangSmith's Agent Server, how does time-travel debugging change?Sometimes asked
The concepts stay the same. Threads, checkpoints, history, updating state and running from a checkpoint are exposed through the server's API and the LangGraph SDK rather than by calling the compiled graph in-process. That makes inspection convenient, but it also means debug calls would run against the deployed graph and its real tools. So I would not fork production threads on the production deployment. Instead, I would run a separate debug deployment or a local graph with sandboxed tools, and bring the thread state over to it. Access to the production API should be limited to read operations for most engineers, with any state-changing operations audited.
Sourced from Docs by LangChain (MCP)
32How do checkpoint_id and parent_config let you reconstruct the branch structure of a thread?Sometimes asked
Every snapshot's config includes the thread_id and its own checkpoint_id, and parent_config points to the checkpoint it was derived from. Following parent links from any checkpoint gives the path back to the thread's first input. When I fork with update_state, the new checkpoint's parent is the older snapshot I forked from, so the thread now has two children under that parent: the original continuation and my fork. Listing history and grouping by parent shows the branches. This is how I keep track of the original run, the replay and each fork while comparing them. It also lets me always return to the original production path.
Sourced from Docs by LangChain (MCP)
33How would you explain the value of time-travel debugging to a product manager who asks why logs are not enough?Sometimes asked
Logs tell you what happened. Time travel lets you rewind to the exact moment before the mistake and run it again with one thing changed. Because the agent's full memory is saved at every step, we can say 'if the order lookup had returned the right data here, would the agent have answered correctly?' and get a real answer in minutes, without touching any real customer or payment system. That turns guesswork into a controlled experiment. We then save that conversation as a permanent test, so any future prompt or model change that brings the bug back is caught before release. The result is faster fixes, fewer repeat incidents and better evidence when explaining what went wrong.
Sourced from Docs by LangChain (MCP)
Objective questions 33
1What happens when you call graph.invoke(None, config) where config contains a past checkpoint_id?Asked almost every time
Why: Replaying from a checkpoint reuses the recorded steps before it and re-executes the steps after it, which creates a new branch of history.
Sourced from Docs by LangChain (MCP)
2Which method returns the list of past StateSnapshots for a thread?Asked almost every time
Why: get_state_history yields the StateSnapshots stored for the thread_id in the config, newest first.
Sourced from Docs by LangChain (MCP)
3Which value in snapshot.config identifies a specific checkpoint within a thread?Asked almost every time
Why: The config carries thread_id and checkpoint_id under configurable, and checkpoint_id selects the exact checkpoint.
Sourced from Docs by LangChain (MCP)
4What does graph.update_state(snapshot.config, values, as_node="tools") do to the original history?Asked almost every time
Why: update_state creates a new checkpoint whose parent is the selected one, so the original checkpoints are preserved.
Sourced from Docs by LangChain (MCP)
5When injecting a corrected tool result, which field of the ToolMessage must match the pending tool call?Asked almost every time
Why: The ToolMessage must reference the AIMessage's tool call via tool_call_id so the model and provider accept it as the answer to that call.
Sourced from Docs by LangChain (MCP)
6What is the most direct way to stop a replay from issuing real refunds?Asked almost every time
Why: Nodes after the checkpoint really execute during replay, so side-effecting tools must be replaced in the debug copy.
Sourced from Docs by LangChain (MCP)
7Why pass as_node="tools" to update_state when forking with a substituted tool result?Very often asked
Why: as_node tells LangGraph which node the update comes from, which determines the next node to run. Without it, LangGraph has to infer the writer, and routing may be wrong.
Sourced from Docs by LangChain (MCP)
8What does snapshot.next == ('tools',) indicate?Very often asked
Why: next lists the nodes scheduled to run after this checkpoint, so a pending tool call is about to execute.
Sourced from Docs by LangChain (MCP)
9When replaying from a past checkpoint, what input do you pass to graph.invoke?Very often asked
Why: Passing None with a config that holds a checkpoint_id continues from that saved state instead of starting with new input.
Sourced from Docs by LangChain (MCP)
10How often does a LangGraph checkpointer save state for a thread?Very often asked
Why: Checkpointers save state per thread_id at every super-step, which is what enables durable execution and time travel.
Sourced from Docs by LangChain (MCP)
11Which stream mode emits each node's state delta as it runs?Very often asked
Why: updates streams the state changes produced by each node, which suits watching a fork resume step by step.
Sourced from Docs by LangChain (MCP)
12What is the main difference between a Store and a checkpointer?Very often asked
Why: Checkpointers persist thread state for durability and time travel, while Stores hold cross-thread memory organised by namespace.
Sourced from Docs by LangChain (MCP)
13The original run and the replay both fail, but the fork with a corrected tool result answers correctly. What is the likely cause?Very often asked
Why: Only the tool result changed between the failing runs and the fork, so the tool data caused the failure.
Sourced from Docs by LangChain (MCP)
14A fork with a correct tool result still produces the wrong refund answer. Where should you look next?Very often asked
Why: If the agent fails even with good data, its reasoning, meaning the prompt or model logic, is at fault.
Sourced from Docs by LangChain (MCP)
15During a replay from a past checkpoint, which nodes actually execute?Very often asked
Why: Steps before the checkpoint are not re-executed, and nodes after it run again.
Sourced from Docs by LangChain (MCP)
16Where does this workflow lock in the fix before shipping?Very often asked
Why: The failing input becomes a regression example that is re-run to confirm the fix and to catch any future regression.
Sourced from Docs by LangChain (MCP)
17Where does the thread_id go in the config passed to get_state_history?Very often asked
Why: LangGraph reads the thread_id from the configurable section, as in {"configurable": {"thread_id": tid}}.
Sourced from Docs by LangChain (MCP)
18In what order does get_state_history return StateSnapshots for a thread?Often asked
Why: get_state_history yields snapshots in reverse chronological order, so the latest checkpoint comes first and you walk backwards to earlier steps.
Sourced from Docs by LangChain (MCP)
19Which checkpointer is intended for local development rather than production?Often asked
Why: InMemorySaver keeps checkpoints in process memory for development, and Postgres is used in production. The two Store options are for long-term memory, not checkpoints.
Sourced from Docs by LangChain (MCP)
20Which stream mode streams LLM tokens together with node metadata?Often asked
Why: messages mode streams LLM tokens along with metadata about the node that produced them.
Sourced from Docs by LangChain (MCP)
21In a typed LangGraph state, what does annotating a list key with operator.add do?Often asked
Why: operator.add is a reducer that concatenates the update onto the current list instead of overwriting it.
Sourced from Docs by LangChain (MCP)
22How do you continue a graph that paused at interrupt()?Often asked
Why: interrupt() pauses for human input, and Command(resume=value) supplies the value and continues execution.
Sourced from Docs by LangChain (MCP)
23What is a Send object returned from a conditional edge used for?Often asked
Why: Send lets a conditional edge dispatch several invocations of a node, each with its own state, for map-reduce patterns.
Sourced from Docs by LangChain (MCP)
24What does returning Command(goto=..., update=...) from a node do?Often asked
Why: Command with goto and update combines routing and state updates, which is how handoffs work.
Sourced from Docs by LangChain (MCP)
25Several replays from the same checkpoint give different final replies. What does this suggest?Often asked
Why: Identical saved state that produces different outcomes points to sampling variance in the model calls that re-run.
Sourced from Docs by LangChain (MCP)
26What does the step field in a snapshot's metadata represent?Often asked
Why: Metadata step records which super-step produced the checkpoint, which helps order and interpret the history.
Sourced from Docs by LangChain (MCP)
27Which checkpointer do the reference notes recommend for production?Often asked
Why: Postgres provides durable, shared checkpoints in production. InMemorySaver is for development.
Sourced from Docs by LangChain (MCP)
28Which production-side control prevents duplicate refunds even if a replay somehow reached the payment API?Often asked
Why: Idempotency keys let the payment service deduplicate repeated requests, which adds defence in depth beyond sandboxed tools.
Sourced from Docs by LangChain (MCP)
29A node writes to a PostgresStore during a replay. What happens to that write if you later fork the thread?Often asked
Why: Time travel operates on checkpoints, not on the cross-thread Store, so the debug copy should use a separate, sandboxed store.
Sourced from Docs by LangChain (MCP)
30How are items in a LangGraph Store organised?Sometimes asked
Why: Stores organise memories under namespace tuples, with optional semantic search.
Sourced from Docs by LangChain (MCP)
31At which path does LangSmith's Agent Server expose an MCP endpoint for a deployed agent?Sometimes asked
Why: Agents deployed on the Agent Server are exposed over an API and an MCP endpoint at /mcp.
Sourced from Docs by LangChain (MCP)
32Which of these is NOT a LangGraph streaming mode listed in the reference notes?Sometimes asked
Why: The notes list values, updates, messages, custom and debug. Replay is done with invoke or stream on a checkpoint config, not with a stream mode.
Sourced from Docs by LangChain (MCP)
33What does update_state return that you use to resume the fork?Sometimes asked
Why: update_state returns a config for the new checkpoint, which is then passed to graph.stream(None, fork_config) to resume.
Sourced from Docs by LangChain (MCP)
Track your progress through every blueprint in your dashboard.
Start learning