bytedance/deer-flow · error · CheckpointModeMismatchError
Thread requires delta mode; materialize and convert its chec
Error message
Thread requires delta mode; materialize and convert its checkpoints before using full mode.
What it means
CheckpointModeMismatchError raised by the delta-gating checkpointer wrapper: the thread's checkpoints use the delta (incremental) format, but the accessor was constructed in full mode. Full-mode reads would silently serve partial state, so any aget/ahistory touching a delta checkpoint raises instead. Writes are not supported on this wrapper; mutation paths use the graph-backed accessor.
Source
Thrown at backend/app/gateway/services.py:771
class _RawCheckpointReadAccessor:
"""Degraded full-mode read accessor for when the agent factory is down.
Full-mode checkpoints persist complete ``channel_values``, so reads do not
need the compiled graph. The fail-closed delta gate still applies: delta
checkpoints are rejected with :class:`CheckpointModeMismatchError` instead
of being served as partial state. Writes are unsupported — mutation paths
keep using the graph-backed accessor.
"""
def __init__(self, checkpointer: Any, mode: str) -> None:
self.checkpointer = checkpointer
self.mode = mode
@staticmethod
def _gate(tup: Any) -> None:
if checkpoint_tuple_uses_delta(tup):
raise CheckpointModeMismatchError("Thread requires delta mode; materialize and convert its checkpoints before using full mode.")
async def aget(self, config: dict[str, Any]) -> _RawCheckpointSnapshot:
tup = await self.checkpointer.aget_tuple(config)
self._gate(tup)
return _RawCheckpointSnapshot(config, tup)
async def ahistory(self, config: dict[str, Any], *, limit: int | None = None) -> list[_RawCheckpointSnapshot]:
if limit is not None and limit <= 0:
return []
result: list[_RawCheckpointSnapshot] = []
before = None
walk_config = config
if config.get("configurable", {}).get("checkpoint_id"):
# Pregel's get_state_history treats config.checkpoint_id as the
# inclusive start of the walk, while alist(before=...) is
# exclusive — fetch the anchor explicitly so the degraded path
# matches the graph path.
before = configView on GitHub (pinned to 1dd6ba1acb)
Solutions
- Materialize and convert the thread's checkpoints from delta to full format using DeerFlow's checkpoint conversion/migration tooling, then retry.
- Serve reads for that thread through delta mode (the accessor mode that matches how it was written).
- Avoid mixed versions writing/reading the same thread store; upgrade all gateway replicas together.
Defensive patterns
Strategy: fallback
Try / catch
catch CheckpointModeMismatchError; fall back to delta-mode reads for that thread, and schedule checkpoint conversion before retrying full mode.
Prevention
- Run DeerFlow's checkpoint conversion/migration whenever upgrading across the format change; don't stop halfway.
- Never run mixed gateway versions against one thread store.
- Gate full-mode state reads behind a post-migration check.
When it happens
Trigger: Reading state/history of a thread created or written by a DeerFlow version that stores delta checkpoints, through a code path that requests full-mode snapshots (e.g. a state or history endpoint configured for full mode).
Common situations: Upgrading/migrating between DeerFlow versions where the checkpoint format changed to delta; mixed-version deployments where one gateway writes deltas and another reads in full mode; running a migration halfway.
Related errors
- Failed to update agent: ${res.statusText}
- Failed to delete agent: ${res.statusText}
- Agent '{name}' only exists in the legacy shared layout and i
- Agent '{name}' only exists in the legacy shared layout and i
- checkpoint must be an object
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/725f3ce4aab831d1.
Report an issue: GitHub.