{"record":{"id":"0f505e5e0777c679","repo":"langchain-ai/langchain","slug":"function-func-contains-a-mix-of-pydantic-v1-and","errorCode":null,"errorMessage":"Function {func} contains a mix of Pydantic v1 and v2 annotations. Only one version of Pydantic annotations per function is supported.","messagePattern":"Function (.+?) contains a mix of Pydantic v1 and v2 annotations\\. Only one version of Pydantic annotations per function is supported\\.","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/tools/base.py","lineNumber":250,"sourceCode":"        True if all Pydantic annotations are from v1, `False` otherwise.\n\n    Raises:\n        NotImplementedError: If the function contains mixed v1 and v2 annotations.\n    \"\"\"\n    any_v1_annotations = any(\n        _is_pydantic_annotation(parameter.annotation, pydantic_version=\"v1\")\n        for parameter in signature.parameters.values()\n    )\n    any_v2_annotations = any(\n        _is_pydantic_annotation(parameter.annotation, pydantic_version=\"v2\")\n        for parameter in signature.parameters.values()\n    )\n    if any_v1_annotations and any_v2_annotations:\n        msg = (\n            f\"Function {func} contains a mix of Pydantic v1 and v2 annotations. \"\n            \"Only one version of Pydantic annotations per function is supported.\"\n        )\n        raise NotImplementedError(msg)\n    return any_v1_annotations and not any_v2_annotations\n\n\nclass _SchemaConfig:\n    \"\"\"Configuration for Pydantic models generated from function signatures.\"\"\"\n\n    extra: str = \"forbid\"\n    \"\"\"Whether to allow extra fields in the model.\"\"\"\n\n    arbitrary_types_allowed: bool = True\n    \"\"\"Whether to allow arbitrary types in the model.\"\"\"\n\n\ndef create_schema_from_function(\n    model_name: str,\n    func: Callable[..., Any],\n    *,\n    filter_args: Sequence[str] | None = None,","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/tools/base.py#L232-L268","documentation":"When inferring a tool schema from a function, langchain checks each parameter annotation for Pydantic v1 vs v2 models and refuses functions that mix both (e.g. one arg annotated with a `pydantic.v1.BaseModel` subclass and another with a `pydantic.BaseModel` subclass), raising NotImplementedError because a single schema cannot be generated across both major versions.","triggerScenarios":"`@tool def f(a: MyV1Model, b: MyV2Model)` where `MyV1Model` inherits `pydantic.v1.BaseModel`; a function annotated with a model imported from a package still on Pydantic v1 alongside a locally-defined v2 model.","commonSituations":"Migrating a codebase (or a dependency) to Pydantic v2 while some imports still resolve to `pydantic.v1`; partner/integration packages that expose v1 models; notebooks where an old model class lingers after upgrading pydantic.","solutions":["Migrate all parameter models to one Pydantic major version — preferably v2 (`pydantic.BaseModel`).","Check each annotation's module (`type(x).__module__`) to find the v1 stragglers, often imported from a dependency pinned to `pydantic.v1`.","If a dependency only offers v1 models, wrap its inputs in a plain v2 model or primitive types at the tool boundary.","If mixed versions are unavoidable, supply an explicit `args_schema` (single-version) instead of relying on inference."],"exampleFix":"# before\nfrom pydantic.v1 import BaseModel as V1Base\nfrom pydantic import BaseModel\n\nclass A(V1Base): x: int\nclass B(BaseModel): y: int\n\n@tool\ndef f(a: A, b: B) -> str: ...  # NotImplementedError\n# after\nfrom pydantic import BaseModel\n\nclass A(BaseModel): x: int\nclass B(BaseModel): y: int\n\n@tool\ndef f(a: A, b: B) -> str: ...","handlingStrategy":"type-guard","validationCode":"import inspect, pydantic\n\ndef annotations_single_pydantic_version(fn) -> bool:\n    versions = set()\n    for p in inspect.signature(fn).parameters.values():\n        ann = p.annotation\n        mod = getattr(ann, '__module__', '')\n        if 'pydantic' in mod:\n            versions.add('v1' if mod.startswith('pydantic.v1') else 'v2')\n    return len(versions) <= 1\n\nassert annotations_single_pydantic_version(fn)","typeGuard":"import pydantic, pydantic.v1\n\ndef is_pydantic_v2_model(cls) -> bool:\n    return inspect.isclass(cls) and issubclass(cls, pydantic.BaseModel)\n\ndef is_pydantic_v1_model(cls) -> bool:\n    return inspect.isclass(cls) and issubclass(cls, pydantic.v1.BaseModel)","tryCatchPattern":"try:\n    t = tool(fn)\nexcept NotImplementedError as e:\n    if 'Pydantic v1 and v2' in str(e):\n        fn = migrate_annotations_to_v2(fn)  # retype params, then retry\n        t = tool(fn)\n    else:\n        raise","preventionTips":["Migrate all models to pydantic v2; grep for 'pydantic.v1' imports.","Check type(x).__module__ of annotation models when mixing dependencies.","Supply explicit args_schema when a dependency is stuck on v1."],"tags":["tool","pydantic","pydantic-v1-migration","annotations"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}