pydantic/pydantic · error · PydanticUserError

config-both

config-both

Error message

"Config" and "model_config" cannot be used together

What it means

Pydantic V2 supports two ways to configure a model: the legacy V1 inner `class Config` and the new `model_config = ConfigDict(...)`. They are mutually exclusive. In ConfigWrapper.for_model (line 171-172), if both `Config` and `model_config` are present in the class namespace, PydanticUserError with code config-both is raised because mixing them creates ambiguity about which settings win.

Source

Thrown at pydantic/_internal/_config.py:172

            A `ConfigWrapper` instance for `BaseModel`.
        """
        config_new = ConfigDict()
        for base in bases:
            config = getattr(base, 'model_config', None)
            if config:
                config_new.update(config.copy())

        config_class_from_namespace = namespace.get('Config')
        config_dict_from_namespace = namespace.get('model_config')

        if raw_annotations.get('model_config') and config_dict_from_namespace is None:
            raise PydanticUserError(
                '`model_config` cannot be used as a model field name. Use `model_config` for model configuration.',
                code='model-config-invalid-field-name',
            )

        if config_class_from_namespace and config_dict_from_namespace:
            raise PydanticUserError('"Config" and "model_config" cannot be used together', code='config-both')

        config_from_namespace = config_dict_from_namespace or prepare_config(config_class_from_namespace)

        config_new.update(config_from_namespace)

        for k in list(kwargs.keys()):
            if k in config_keys:
                config_new[k] = kwargs.pop(k)

        return cls(config_new)

    # we don't show `__getattr__` to type checkers so missing attributes cause errors
    if not TYPE_CHECKING:  # pragma: no branch

        def __getattr__(self, name: str) -> Any:
            try:
                return self.config_dict[name]
            except KeyError:

View on GitHub (pinned to 2e5f0e2b42)

Solutions

  1. Remove the legacy `class Config:` block and keep only `model_config = ConfigDict(...)`.
  2. Alternatively, keep `class Config:` only (deprecated, warns) and remove model_config — but the recommended path is the V2 ConfigDict.
  3. If config came from a base class, override it consistently in one style in the subclass.

Example fix

# before
class M(BaseModel):
    class Config:
        frozen = True
    model_config = ConfigDict(str_strip_whitespace=True)

# after
class M(BaseModel):
    model_config = ConfigDict(frozen=True, str_strip_whitespace=True)
Defensive patterns

Strategy: validation

Validate before calling

def check_single_config_style(namespace: dict) -> None:
    if 'Config' in namespace and 'model_config' in namespace:
        raise TypeError('Define either Config or model_config, not both')

Type guard

def uses_single_config_style(cls_dict: dict) -> bool:
    return not ('Config' in cls_dict and 'model_config' in cls_dict)

Try / catch

try:
    class M(BaseModel): ...
except PydanticUserError as e:
    if e.code == 'config-both':
        # delete the inner class Config and keep model_config
        raise
    raise

Prevention

When it happens

Trigger: Defining a model that contains both an inner `class Config:` (V1 style) and a `model_config = ConfigDict(...)` (V2 style) at the same class level. Also occurs via inheritance if a base defines one style and the subclass adds the other in the same namespace block being processed.

Common situations: Partially migrating a V1 model: developer adds model_config but forgets to delete the old Config class; copy-pasting a V1 model and appending V2 config on top.

Related errors


AI-assisted analysis of pydantic/pydantic@2e5f0e2b42 (2026-08-04). Data as JSON: /data/errors/ce0bb2c3c10104d0.json. Report an issue: GitHub.