langchain-ai/deepagents · error · ValueError
Hook resume snapshot_id mismatch: expected {snapshot_id}, go
Error message
Hook resume snapshot_id mismatch: expected {snapshot_id}, got {response.snapshot_id} What it means
parse_hook_resume_value also verifies that the resume payload's snapshot_id matches the snapshot captured when the hook interrupt was raised. snapshot_id ties the resume to the exact state the hook saw; a mismatch means the agent state has changed since the interrupt (new snapshot taken) and the stale resume is rejected with ValueError.
Source
Thrown at libs/code/deepagents_code/hooks/interrupt.py:113
Returns:
Validated response.
Raises:
ValueError: If the resume payload is missing, mistyped, or mismatched.
"""
response = HOOK_INVOCATION_RESPONSE_ADAPTER.validate_python(value)
if response.invocation_id != invocation_id:
msg = (
f"Hook resume invocation_id mismatch: expected {invocation_id}, "
f"got {response.invocation_id}"
)
raise ValueError(msg)
if response.snapshot_id != snapshot_id:
msg = (
f"Hook resume snapshot_id mismatch: expected {snapshot_id}, "
f"got {response.snapshot_id}"
)
raise ValueError(msg)
return response
def is_hook_interrupt_payload(value: object) -> bool:
"""Return whether `value` looks like a Hooks v2 invocation interrupt."""
return (
isinstance(value, dict) and value.get("type") == HOOK_INVOCATION_INTERRUPT_TYPE
)
View on GitHub (pinned to a1af029e6e)
Solutions
- Obtain a fresh interrupt payload and use its snapshot_id and invocation_id together when resuming
- Discard resume values saved before the latest checkpoint and re-answer the hook prompt
- When replaying checkpoints, replay the corresponding hook resume from the same checkpoint, not a newer one
- If this fires consistently after retries, verify the runtime preserves snapshot ids across graph re-entry or upgrade the runtime
Example fix
// before resume = parse_hook_resume_value(old_payload, invocation_id, current_snapshot_id) // after payload = pending_interrupts[invocation_id] # payload carries its own snapshot_id resume = parse_hook_resume_value(payload.resume_value, invocation_id, payload.snapshot_id)
Defensive patterns
Strategy: validation
Validate before calling
if resume_payload.get("snapshot_id") != expected_snapshot_id:
raise ValueError("resume references an outdated snapshot; re-answer the hook")
Type guard
def matches_snapshot(payload: dict, snapshot_id: str) -> bool:
return payload.get("snapshot_id") == snapshot_id
Try / catch
try:
resume = parse_hook_resume_value(payload, invocation_id, snapshot_id)
except ValueError as exc:
logger.error("snapshot mismatch: %s", exc)
resume = prompt_user_again(invocation_id) # discard stale answer
Prevention
- Treat invocation_id + snapshot_id as an inseparable pair when storing resumes
- After a checkpoint/time-travel, regenerate hook resumes from the checkpointed state
- Never replay resume payloads recorded before the latest snapshot
When it happens
Trigger: Resuming a hook interrupt whose payload references a snapshot_id different from the expected one — typically after the agent checkpointed a new snapshot between the original interrupt and the resume, or when replaying a resume value saved from a previous run.
Common situations: Time-travel/checkpoint replay in langgraph-based flows resuming from an older snapshot; stale TUI state after graph re-invocation; multiple pending interrupts resolved out of order so payload/snapshot pairs get crossed.
Related errors
- Hook resume invocation_id mismatch: expected {invocation_id}
- Permission interrupted by hook
- Received hook invocation interrupt without a HooksRuntime
- Failed to parse hook interrupt
- Provided snapshot_id does not match canonical configuration
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/f2e9f80fc9e03ce3.
Report an issue: GitHub.