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
- Remove the legacy `class Config:` block and keep only `model_config = ConfigDict(...)`.
- Alternatively, keep `class Config:` only (deprecated, warns) and remove model_config — but the recommended path is the V2 ConfigDict.
- 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
- Standardize on model_config = ConfigDict(...) and delete any V1 Config class.
- During migration, search for 'class Config' inside model definitions and remove them.
- Do not mix config styles across base and subclass.
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
- model-config-invalid-field-name
- Config has no attribute {name!r}
- validate-by-alias-and-name-false
- validator-field-config-info
- validator-v1-signature
AI-assisted analysis of pydantic/pydantic@2e5f0e2b42 (2026-08-04).
Data as JSON: /data/errors/ce0bb2c3c10104d0.json.
Report an issue: GitHub.