langchain-ai/langchain · error · TypeError

Expected 'type' to be a str, got {type(result).__name__}

Error message

Expected 'type' to be a str, got {type(result).__name__}

What it means

Raised by `_get_type` when the value found at `v['type']` (or `v.type`) is not a Python `str`. The discriminator must be a string like 'human' or 'ai'; any other type (int, None, list) is rejected to keep serialization dispatch deterministic.

Source

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

logger = logging.getLogger(__name__)


def _get_type(v: Any) -> str:
    """Get the type associated with the object for serialization purposes."""
    if isinstance(v, dict) and "type" in v:
        result = v["type"]
    elif hasattr(v, "type"):
        result = v.type
    else:
        msg = (
            f"Expected either a dictionary with a 'type' key or an object "
            f"with a 'type' attribute. Instead got type {type(v)}."
        )
        raise TypeError(msg)
    if not isinstance(result, str):
        msg = f"Expected 'type' to be a str, got {type(result).__name__}"
        raise TypeError(msg)
    return result


AnyMessage = Annotated[
    Annotated[AIMessage, Tag(tag="ai")]
    | Annotated[HumanMessage, Tag(tag="human")]
    | Annotated[ChatMessage, Tag(tag="chat")]
    | Annotated[SystemMessage, Tag(tag="system")]
    | Annotated[FunctionMessage, Tag(tag="function")]
    | Annotated[ToolMessage, Tag(tag="tool")]
    | Annotated[AIMessageChunk, Tag(tag="AIMessageChunk")]
    | Annotated[HumanMessageChunk, Tag(tag="HumanMessageChunk")]
    | Annotated[ChatMessageChunk, Tag(tag="ChatMessageChunk")]
    | Annotated[SystemMessageChunk, Tag(tag="SystemMessageChunk")]
    | Annotated[FunctionMessageChunk, Tag(tag="FunctionMessageChunk")]
    | Annotated[ToolMessageChunk, Tag(tag="ToolMessageChunk")],
    Field(discriminator=Discriminator(_get_type)),
]

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Ensure the 'type' value is a plain string literal ('human', 'ai', 'system', 'chat', 'function', 'tool')
  2. Coerce before passing: `{'type': str(v['type']), ...}` if the source data uses stringly-typed numbers or enums
  3. Fix custom message classes so the `type` attribute is a `str` (langchain-core's own classes use `Literal` string values)

Example fix

# before
msg = {'type': None, 'content': 'hi'}

# after
msg = {'type': 'human', 'content': 'hi'}
Defensive patterns

Strategy: validation

Validate before calling

def valid_type_value(v) -> bool:
    t = v.get('type') if isinstance(v, dict) else getattr(v, 'type', None)
    return isinstance(t, str) and len(t) > 0

Type guard

def is_str_typed(v: dict) -> bool:
    return isinstance(v.get('type'), str)

Try / catch

try:
    result = _get_type(v)
except TypeError as e:
    if "Expected 'type' to be a str" in str(e):
        if isinstance(v, dict):
            v['type'] = str(v['type'])
        result = _get_type(v)
    else:
        raise

Prevention

When it happens

Trigger: A message dict like `{'type': 1, ...}` or `{'type': None, ...}`, or an object whose `.type` attribute is a non-string (e.g. an int enum or a property returning None).

Common situations: Programmatically generated message dicts where the type was inserted from an untyped source (JSON number); ORM rows where `type` maps to an integer column; custom message classes overriding `type` with a non-string value.

Related errors


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