langchain-ai/deepagents · error · TypeError
LangGraph returned a non-list messages channel.
Error message
LangGraph returned a non-list messages channel.
What it means
The hydrated thread state's `messages` channel must be a list; the SDK converts each entry to a message object via convert_to_messages. If LangGraph reports a non-list messages channel, the state shape is invalid and _hydrate_state raises this TypeError instead of iterating over something that cannot be converted. Like the non-object state error, it points to a server/runtime or state-corruption problem.
Source
Thrown at libs/code/deepagents_code/offload_api.py:557
"""Hydrate serialized checkpoint messages for the compaction service.
Args:
values: State values returned by LangGraph Server.
Returns:
A shallow state copy containing LangChain message objects.
Raises:
TypeError: If the server returns an unexpected state shape.
"""
if not isinstance(values, dict):
msg = "LangGraph returned non-object thread state."
raise TypeError(msg)
state = dict(values)
messages = state.get("messages", [])
if not isinstance(messages, list):
msg = "LangGraph returned a non-list messages channel."
raise TypeError(msg)
state["messages"] = convert_to_messages(messages)
# LangGraph serializes the summary stored inside the private event channel
# independently of the top-level `messages` channel. The summarization SDK
# prepends it to the effective conversation, so it must be a message object
# too rather than the serialized dict returned by the thread API.
event = state.get("_summarization_event")
if isinstance(event, Mapping) and "summary_message" in event:
hydrated_event = dict(event)
summary_message = hydrated_event["summary_message"]
hydrated_event["summary_message"] = convert_to_messages([summary_message])[0]
state["_summarization_event"] = hydrated_event
return cast("_OffloadState", state)
def _checkpoint_model_context(
context: dict[str, Any], state: Mapping[str, object]
) -> dict[str, Any]:View on GitHub (pinned to a1af029e6e)
Solutions
- Check the thread's checkpoint/state integrity; recover from an earlier checkpoint or start a new thread if messages is corrupted.
- Ensure the deployed graph uses the standard add_messages/messages list channel the SDK expects; align graph and SDK versions.
- Log the raw get_state values to see the actual channel type; fix or migrate the stored state.
- In tests, make fake get_state return {'messages': [], ...} as a dict of channels.
Example fix
// before
values = await client.threads.get_state(thread_id) # returns {'messages': {'0': {...}}}
// after
# repair/migrate the channel before offloading
if not isinstance(values.get("messages"), list):
values["messages"] = list(values["messages"].values())
state = await offload(thread_id, payload) Defensive patterns
Strategy: try-catch
Validate before calling
state = await client.threads.get_state(thread_id)
messages = state.get("messages", []) if isinstance(state, dict) else []
if not isinstance(messages, list):
raise RuntimeError(f"Thread {thread_id} has a corrupt 'messages' channel") Type guard
def has_message_list(state) -> bool:
return isinstance(state, dict) and isinstance(state.get("messages", []), list) Try / catch
try:
state = await offload(thread_id, payload)
except TypeError as exc:
if "non-list messages channel" in str(exc):
raise RuntimeError(
f"Thread {thread_id} 'messages' channel is corrupt; recover from an earlier checkpoint"
) from exc
raise Prevention
- Use the standard messages list channel (add_messages) in your graph definition
- Avoid hand-editing checkpoints or channel values
- Keep graph and SDK versions aligned so channel types match expectations
- In tests, make get_state fakes return {'messages': [], ...} with correct shapes
When it happens
Trigger: _execute_offload hydrating state where state.get('messages') came back as a dict, string, or None (key present with wrong type) instead of a list.
Common situations: A thread server storing messages in a legacy/custom channel format, a manually edited or corrupted checkpoint where messages was overwritten, an incompatible graph definition whose 'messages' channel is not a list-typed channel, or a mock returning the wrong shape in tests.
Related errors
- LangGraph returned non-object thread state.
- -32002
- SHELL_ALLOW_ALL should not be used with ShellAllowListMiddle
- interpreter_ptc must be False, 'safe', 'all', or a list of t
- --model-params must be a JSON object, got {type}
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/e9223a0f05942795.
Report an issue: GitHub.