langchain-ai/langchain · error · TypeError

Expected a Pydantic model. Got {model}

Error message

Expected a Pydantic model. Got {model}

What it means

Raised by `get_fields` in `langchain_core.utils.pydantic` when the argument is neither a pydantic v1 nor v2 `BaseModel` (class or instance). The utility introspects `.model_fields` (v2) or `__fields__` (v1); anything else — dataclasses, TypedDicts, plain classes, primitives — is rejected with `TypeError`. It typically surfaces indirectly when passing a non-pydantic schema object into LangChain APIs that expect a pydantic model.

Source

Thrown at libs/core/langchain_core/utils/pydantic.py:347

def get_fields(
    model: type[BaseModel | BaseModelV1] | BaseModel | BaseModelV1,
) -> dict[str, FieldInfoV2] | dict[str, ModelField]:
    """Return the field names of a Pydantic model.

    Args:
        model: The Pydantic model or instance.

    Raises:
        TypeError: If the model is not a Pydantic model.
    """
    if not isinstance(model, type):
        model = type(model)
    if issubclass(model, BaseModel):
        return model.model_fields
    if issubclass(model, BaseModelV1):
        return model.__fields__
    msg = f"Expected a Pydantic model. Got {model}"  # type: ignore[unreachable]
    raise TypeError(msg)


def model_json_schema(model: TypeBaseModel) -> dict[str, Any]:
    """Return the JSON schema of a Pydantic model class of either major version.

    Dispatches to the correct method for Pydantic v1 (`schema`) or v2
    (`model_json_schema`), so callers holding a `TypeBaseModel` don't have to
    branch on the model's version themselves.

    Args:
        model: The Pydantic model class.

    Raises:
        TypeError: If the model is not a Pydantic model class.
    """
    if issubclass(model, BaseModel):
        return model.model_json_schema()
    if issubclass(model, BaseModelV1):

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Convert the argument to a pydantic model: decorate dataclasses with `pydantic.dataclasses.dataclass` won't help here — define a `BaseModel` subclass with the same fields.
  2. If using TypedDict, switch to a pydantic `BaseModel` (or use an API path that accepts JSON Schema directly).
  3. If the value may legitimately vary, branch on `isinstance(obj, BaseModel)` (and pydantic.v1 `BaseModel`) before calling.

Example fix

# before
from dataclasses import dataclass
@dataclass
class Args:
    query: str
get_fields(Args)  # TypeError: Expected a Pydantic model.

# after
from pydantic import BaseModel
class Args(BaseModel):
    query: str
get_fields(Args)
Defensive patterns

Strategy: type-guard

Validate before calling

from pydantic import BaseModel
from pydantic.v1 import BaseModel as BaseModelV1

def has_fields(obj: Any) -> bool:
    cls = obj if isinstance(obj, type) else type(obj)
    return issubclass(cls, (BaseModel, BaseModelV1))

Type guard

from pydantic import BaseModel
from pydantic.v1 import BaseModel as BaseModelV1

def is_pydantic_model(obj: Any) -> TypeGuard[type[BaseModel] | type[BaseModelV1]]:
    cls = obj if isinstance(obj, type) else type(obj)
    return issubclass(cls, (BaseModel, BaseModelV1))

Try / catch

try:
    fields = get_fields(obj)
except TypeError:
    fields = None  # or convert obj to a BaseModel first

Prevention

When it happens

Trigger: Calling `get_fields(obj)` (directly or via APIs that derive field schemas from models, such as tool/structured-output argument parsing) with a dataclass, `TypedDict`, `NamedTuple`, or arbitrary class. Note the function first does `type(model)` on instances, so instances of valid models are fine; only non-model types fail.

Common situations: Migrating code from dataclass-based tools to pydantic-based ones; passing a `TypedDict` where LangChain expects `BaseModel` (e.g. `with_structured_output`, tool args); duck-typed fakes/mocks in tests that are not pydantic models; mixing pydantic v1/v2 where the object is actually an unrelated class.

Related errors


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