{"record":{"id":"fa1ab0eea8921cce","repo":"langchain-ai/langchain","slug":"expected-either-a-dictionary-with-a-type-key-or","errorCode":null,"errorMessage":"Expected either a dictionary with a 'type' key or an object with a 'type' attribute. Instead got type {type(v)}.","messagePattern":"Expected either a dictionary with a 'type' key or an object with a 'type' attribute\\. Instead got type (.+?)\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/messages/utils.py","lineNumber":79,"sourceCode":"    _HAS_LANGCHAIN_TEXT_SPLITTERS = True\nexcept ImportError:\n    _HAS_LANGCHAIN_TEXT_SPLITTERS = False\n\nlogger = logging.getLogger(__name__)\n\n\ndef _get_type(v: Any) -> str:\n    \"\"\"Get the type associated with the object for serialization purposes.\"\"\"\n    if isinstance(v, dict) and \"type\" in v:\n        result = v[\"type\"]\n    elif hasattr(v, \"type\"):\n        result = v.type\n    else:\n        msg = (\n            f\"Expected either a dictionary with a 'type' key or an object \"\n            f\"with a 'type' attribute. Instead got type {type(v)}.\"\n        )\n        raise TypeError(msg)\n    if not isinstance(result, str):\n        msg = f\"Expected 'type' to be a str, got {type(result).__name__}\"\n        raise TypeError(msg)\n    return result\n\n\nAnyMessage = Annotated[\n    Annotated[AIMessage, Tag(tag=\"ai\")]\n    | Annotated[HumanMessage, Tag(tag=\"human\")]\n    | Annotated[ChatMessage, Tag(tag=\"chat\")]\n    | Annotated[SystemMessage, Tag(tag=\"system\")]\n    | Annotated[FunctionMessage, Tag(tag=\"function\")]\n    | Annotated[ToolMessage, Tag(tag=\"tool\")]\n    | Annotated[AIMessageChunk, Tag(tag=\"AIMessageChunk\")]\n    | Annotated[HumanMessageChunk, Tag(tag=\"HumanMessageChunk\")]\n    | Annotated[ChatMessageChunk, Tag(tag=\"ChatMessageChunk\")]\n    | Annotated[SystemMessageChunk, Tag(tag=\"SystemMessageChunk\")]\n    | Annotated[FunctionMessageChunk, Tag(tag=\"FunctionMessageChunk\")]","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/messages/utils.py#L61-L97","documentation":"Raised by the internal helper `_get_type` when a value passed to message serialization/conversion is neither a dict containing a 'type' key nor an object with a `type` attribute. The helper is used to derive the message-type discriminator string during (de)serialization of message-like values.","triggerScenarios":"Passing a plain dict without a 'type' key (e.g. `{'role': 'user', 'content': 'hi'}`) or an arbitrary object without a `.type` attribute into code paths that call `_get_type`, such as message dict round-tripping utilities.","commonSituations":"Hand-built message dicts from OpenAI-style payloads that use 'role' instead of 'type'; custom dataclasses passed where a `BaseMessage` or typed dict is expected; partial JSON loaded from a log with the 'type' field stripped.","solutions":["Add a 'type' key to the dict ('human', 'ai', 'system', 'tool', ...) or rename 'role' to 'type' where the API expects the langchain shape","Pass proper `BaseMessage` instances (`HumanMessage`, `AIMessage`, ...) instead of raw dicts","If using OpenAI-style dicts, use `convert_to_messages`/`convert_to_openai_messages` helpers instead of the serialization path directly"],"exampleFix":"# before\nmsg = {'role': 'user', 'content': 'hi'}\n\n# after\nmsg = {'type': 'human', 'content': 'hi'}\n# or\nfrom langchain_core.messages import HumanMessage\nmsg = HumanMessage('hi')","handlingStrategy":"validation","validationCode":"def has_type_discriminator(v) -> bool:\n    return (isinstance(v, dict) and isinstance(v.get('type'), str)) or (hasattr(v, 'type') and isinstance(getattr(v, 'type'), str))","typeGuard":"from typing import Any\n\ndef is_message_like(v: Any) -> bool:\n    if isinstance(v, dict):\n        return isinstance(v.get('type'), str)\n    return isinstance(getattr(v, 'type', None), str)","tryCatchPattern":"try:\n    t = _get_type(v)\nexcept TypeError:\n    # normalize and retry once with an explicit type\n    v = {**v, 'type': 'human'} if isinstance(v, dict) else v\n    t = _get_type(v)","preventionTips":["Always build messages with BaseMessage classes or dicts containing a string 'type' key","Validate external payloads at the boundary before passing them to langchain","Prefer convert_to_messages for OpenAI-style 'role' dicts"],"tags":["serialization","message-dicts","type-discriminator"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}