langchain-ai/langchain · error · ValueError

Got unexpected message type: {type_}

Error message

Got unexpected message type: {type_}

What it means

Raised by the internal message-deserialization dispatch (used by `messages_from_dict`) when the 'type' string of a serialized message does not match any known class name ('HumanMessage', 'AIMessageChunk', 'ToolMessageChunk', etc.). The deserializer only instantiates from a fixed allowlist of type strings.

Source

Thrown at libs/core/langchain_core/messages/utils.py:544

        return FunctionMessage(**message["data"])
    if type_ == "tool":
        return ToolMessage(**message["data"])
    if type_ == "remove":
        return RemoveMessage(**message["data"])
    if type_ == "AIMessageChunk":
        return AIMessageChunk(**message["data"])
    if type_ == "HumanMessageChunk":
        return HumanMessageChunk(**message["data"])
    if type_ == "FunctionMessageChunk":
        return FunctionMessageChunk(**message["data"])
    if type_ == "ToolMessageChunk":
        return ToolMessageChunk(**message["data"])
    if type_ == "SystemMessageChunk":
        return SystemMessageChunk(**message["data"])
    if type_ == "ChatMessageChunk":
        return ChatMessageChunk(**message["data"])
    msg = f"Got unexpected message type: {type_}"
    raise ValueError(msg)


def messages_from_dict(messages: Sequence[dict[str, Any]]) -> list[BaseMessage]:
    """Convert a sequence of messages from dicts to `Message` objects.

    Args:
        messages: Sequence of messages (as dicts) to convert.

    Returns:
        list of messages (BaseMessages).

    """
    return [_message_from_dict(m) for m in messages]


def message_chunk_to_message(chunk: BaseMessage) -> BaseMessage:
    """Convert a message chunk to a `Message`.

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Check the exact 'type' spelling against the supported list (HumanMessage, AIMessage, SystemMessage, FunctionMessage, ToolMessage, ChatMessage and their Chunk variants)
  2. If data comes from another version, map/normalize type strings before deserializing
  3. Re-serialize messages with the current langchain-core version so type names match

Example fix

# before
messages_from_dict([{'type': 'human_message', 'data': {'content': 'hi'}}])

# after
messages_from_dict([{'type': 'HumanMessage', 'data': {'content': 'hi', 'type': 'human'}}])
Defensive patterns

Strategy: validation

Validate before calling

KNOWN_TYPES = {'HumanMessage', 'AIMessage', 'SystemMessage', 'FunctionMessage',
               'ToolMessage', 'ChatMessage', 'AIMessageChunk', 'HumanMessageChunk',
               'FunctionMessageChunk', 'ToolMessageChunk', 'SystemMessageChunk', 'ChatMessageChunk'}

def deserializable(d: dict) -> bool:
    return d.get('type') in KNOWN_TYPES

Type guard

def is_known_serialized_type(d: dict) -> bool:
    return isinstance(d, dict) and d.get('type') in KNOWN_TYPES

Try / catch

try:
    msgs = messages_from_dict(data)
except ValueError as e:
    if 'unexpected message type' in str(e):
        data = normalize_type_strings(data)  # map old/misspelled names
        msgs = messages_from_dict(data)
    else:
        raise

Prevention

When it happens

Trigger: Calling `messages_from_dict` on dicts whose 'type' field is a misspelled or unknown class name, e.g. `{'type': 'humanmessage', 'data': {...}}` or a type from a newer/older langchain version.

Common situations: Loading chat histories persisted by a different langchain-core version that serialized a class name this version dropped or renamed; hand-edited JSON logs; cross-system message exchange where one side uses non-standard type strings.

Related errors


AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14). Data as JSON: /api/errors/d1ddb9552ad9f526. Report an issue: GitHub.