langchain-ai/langchain · error · NotImplementedError

Remapping for fields starting with '_' or fields with a name

Error message

Remapping for fields starting with '_' or fields with a name matching a reserved name {_RESERVED_NAMES} is not supported if  the field is a pydantic Field instance. Got {key}.

What it means

Raised by `_remap_field_definitions` in `langchain_core.utils.pydantic` (used by `create_model`-style dynamic model creation) when a field name starts with `_` or collides with a pydantic-reserved name (`model_`-prefixed / internal names in `_RESERVED_NAMES`) AND the field value is a pydantic `FieldInfo` (i.e. `Field(...)`). Remapping such names relies on re-wrapping a `(type, default)` tuple; it cannot preserve a full `FieldInfo`, so it refuses with `NotImplementedError` instead of silently dropping constraints.

Source

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

# "model_fields_set", "model_json_schema", "model_parametrized_name",
# "model_post_init", "model_rebuild", "model_validate", "model_validate_json",
# "model_validate_strings"
_RESERVED_NAMES = {key for key in dir(BaseModel) if not key.startswith("_")}


def _remap_field_definitions(field_definitions: dict[str, Any]) -> dict[str, Any]:
    """This remaps fields to avoid colliding with internal pydantic fields."""
    remapped = {}
    for key, value in field_definitions.items():
        if key.startswith("_") or key in _RESERVED_NAMES:
            # Let's add a prefix to avoid colliding with internal pydantic fields
            if isinstance(value, FieldInfoV2):
                msg = (
                    f"Remapping for fields starting with '_' or fields with a name "
                    f"matching a reserved name {_RESERVED_NAMES} is not supported if "
                    f" the field is a pydantic Field instance. Got {key}."
                )
                raise NotImplementedError(msg)
            type_, default_ = value
            remapped[f"private_{key}"] = (
                type_,
                Field(
                    default=default_,
                    alias=key,
                    serialization_alias=key,
                    title=key.lstrip("_").replace("_", " ").title(),
                ),
            )
        else:
            remapped[key] = value
    return remapped


def create_model_v2(
    model_name: str,
    *,

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Rename the field so it does not start with `_` and is not in `_RESERVED_NAMES` (preferred — remapping then works and keeps an alias).
  2. If renaming is impossible, define the field as a plain tuple `(type, default)` instead of `Field(...)`; the helper can then remap it with an alias preserving the original name.
  3. Pre-normalize external field names (strip leading underscores, prefix reserved names) before generating the model.

Example fix

# before
create_model("M", **{"_count": (int, Field(default=0, ge=0))})  # NotImplementedError

# after
create_model("M", **{"_count": (int, 0)})  # tuple form: remapped with alias '_count'
# or better: rename
create_model("M", count=(int, Field(default=0, ge=0)))
Defensive patterns

Strategy: validation

Validate before calling

from langchain_core.utils.pydantic import _RESERVED_NAMES
from pydantic.fields import FieldInfo

def check_field_defs(field_definitions: dict) -> None:
    for name, value in field_definitions.items():
        if (name.startswith("_") or name in _RESERVED_NAMES) and isinstance(value, FieldInfo):
            raise ValueError(
                f"field {name!r}: reserved/underscore names must use (type, default) tuples, not Field(...)"
            )

Try / catch

try:
    create_model("M", **field_definitions)
except NotImplementedError as e:
    # rewrite offending FieldInfo as (type, default) and retry
    ...

Prevention

When it happens

Trigger: Building a dynamic model (e.g. via `langchain_core.utils.pydantic.create_model` / tool-args model creation) with field definitions like `{"_private": (str, Field(...))}` or `{"model_config_override": Field(default=1, ...)}` — any reserved/underscore name mapped to a `Field(...)` instance rather than a `(type, default)` tuple.

Common situations: Structured-output schemas generated from external specs (OpenAPI, JSON Schema, database columns) that contain leading-underscore or `model_*` column names; converting user-supplied dicts into tool argument models where keys are arbitrary; naming a field `model_fields`, `model_config`, etc.

Related errors


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