langchain-ai/deepagents · error · ValueError
Offload compaction requires checkpointed conversation messag
Error message
Offload compaction requires checkpointed conversation messages.
What it means
Forced compaction planning (`_aplan_forced_compaction_update`) reads `messages` from the checkpointed thread state and requires at least one message to summarize. If the state has no messages, there is nothing to compact, so it raises ValueError instead of producing an empty or malformed update. This guards the `/offload` execute path against running compaction on an empty or unpersisted thread.
Source
Thrown at libs/code/deepagents_code/offload_middleware.py:1447
Args:
state: Checkpointed conversation and prior summarization event.
runtime: Run context carrier used to select the summarizer model.
Returns:
The checkpoint/archive plan, or `None` when nothing can be compacted.
Raises:
ValueError: If called directly with no messages. The owning server
operation handles an empty thread before reaching this helper.
"""
summarization = await asyncio.to_thread(
self._summarization_for_runtime, runtime
)
messages = state.get("messages", [])
event = state.get("_summarization_event")
if not messages:
msg = "Offload compaction requires checkpointed conversation messages."
raise ValueError(msg)
effective = summarization._apply_event_to_messages(messages, event)
cutoff = summarization._determine_cutoff_index(effective)
if cutoff == 0:
return None
# Resolved once and threaded into the update below: the SDK call is the
# relative-to-absolute conversion, and computing it twice would let the
# value checked here drift from the value committed.
state_cutoff = summarization._compute_state_cutoff(event, cutoff)
if state_cutoff <= _event_cutoff(event):
# Degenerate chained compaction: everything eligible is already
# behind the prior event's cutoff, so only the previous summary
# would be re-summarized. Committing would spend a model call to
# replace the in-context summary with a lossier summary-of-a-summary
# and drop the prior `file_path` from the event -- while the client,
# which keys its report on the *absolute* cutoff advancing, still
# reported "nothing to offload". Stop before the model call so the
# report and the state agree.
return NoneView on GitHub (pinned to a1af029e6e)
Solutions
- Only run offload/forced compaction on threads that have checkpointed conversation messages.
- Correct the thread_id/checkpoint_ns so the state resolves to the right thread.
- In tests, provide a state fixture containing at least one message.
Example fix
// before
result = await operation.execute({"_summarization_event": None}, runtime)
// after
state = await client.threads.get_state(thread_id)
if state["messages"]:
result = await operation.execute(state, runtime) Defensive patterns
Strategy: validation
Validate before calling
state = await client.threads.get_state(thread_id)
if not state.get("messages"):
return skipped_result("nothing to offload") Type guard
def has_messages(state: dict[str, Any]) -> bool:
msgs = state.get("messages")
return isinstance(msgs, list) and len(msgs) > 0 Try / catch
try:
result = await operation.execute(state, runtime)
except ValueError as e:
if "checkpointed conversation messages" in str(e):
result = noop_result() # empty thread: nothing to compact
else:
raise Prevention
- Check message count in the UI/API before offering /offload.
- Verify thread_id/configurable keys resolve to the intended thread.
- Include at least one message in test state fixtures for compaction tests.
When it happens
Trigger: Calling `OffloadOperation.execute`/`arun_forced_compaction_update` against a thread whose state dict lacks `messages` or has an empty list — e.g. a brand-new thread, a state loaded from the wrong thread_id, or a test state fixture without messages.
Common situations: Offloading an empty thread via a scripted/API call; misconfigured thread_id pointing at a fresh checkpoint; test doubles that omit the `messages` key.
Related errors
- Offload server completed without a typed result.
- Offload result has no status.
- Offload result field {field!r} must be an integer, got {type
- context.{key} must be a string or null, got {type(value).__n
- context.{key} must be an object, got {type(value).__name__}.
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/05d54bd8c4849593.
Report an issue: GitHub.