pydantic/pydantic · error · ValidationError
{cls.__name__} expected dict not {obj.__class__.__name__}
Error message
{cls.__name__} expected dict not {obj.__class__.__name__} What it means
Raised by BaseModel.parse_obj (main.py:548) when the passed object is not a dict and cannot be converted via dict(obj) (the conversion raises TypeError or ValueError). parse_obj expects a mapping of field name -> value; non-mapping inputs that are not dict-convertible (e.g. a bare int, str, or a non-iterable object) produce this wrapped ValidationError.
Source
Thrown at pydantic/v1/main.py:548
def _enforce_dict_if_root(cls, obj: Any) -> Any:
if cls.__custom_root_type__ and (
not (isinstance(obj, dict) and obj.keys() == {ROOT_KEY})
and not (isinstance(obj, BaseModel) and obj.__fields__.keys() == {ROOT_KEY})
or cls.__fields__[ROOT_KEY].shape in MAPPING_LIKE_SHAPES
):
return {ROOT_KEY: obj}
else:
return obj
@classmethod
def parse_obj(cls: Type['Model'], obj: Any) -> 'Model':
obj = cls._enforce_dict_if_root(obj)
if not isinstance(obj, dict):
try:
obj = dict(obj)
except (TypeError, ValueError) as e:
exc = TypeError(f'{cls.__name__} expected dict not {obj.__class__.__name__}')
raise ValidationError([ErrorWrapper(exc, loc=ROOT_KEY)], cls) from e
return cls(**obj)
@classmethod
def parse_raw(
cls: Type['Model'],
b: StrBytes,
*,
content_type: str = None,
encoding: str = 'utf8',
proto: Protocol = None,
allow_pickle: bool = False,
) -> 'Model':
try:
obj = load_str_bytes(
b,
proto=proto,
content_type=content_type,
encoding=encoding,View on GitHub (pinned to 2e5f0e2b42)
Solutions
- Pass a dict (or a dict-convertible mapping) to parse_obj.
- For ORM objects use Model.from_orm(obj) (with orm_mode=True).
- For scalar/list root values, declare a __root__ field so the value is accepted directly.
- Pre-validate the input shape before calling parse_obj.
Example fix
// before
m = M.parse_obj(42) # raises 'expected dict not int'
// after
m = M.parse_obj({'value': 42})
# or for a scalar root:
class M(BaseModel):
__root__: int
m = M.parse_obj(42) Defensive patterns
Strategy: type-guard
Validate before calling
from typing import Mapping
def is_parseable_obj(obj) -> bool:
return isinstance(obj, Mapping) or _is_dict_convertible(obj)
def _is_dict_convertible(obj) -> bool:
try:
dict(obj)
return True
except (TypeError, ValueError):
return False
# usage
if not is_parseable_obj(payload):
raise TypeError(f'parse_obj expects a dict, got {type(payload).__name__}')
MyModel.parse_obj(payload) Type guard
from typing import Any, Mapping
def is_dict_like(value: Any) -> bool:
if isinstance(value, Mapping):
return True
try:
dict(value)
return True
except (TypeError, ValueError):
return False Try / catch
from pydantic.v1 import ValidationError
try:
m = MyModel.parse_obj(payload)
except ValidationError as e:
if 'expected dict not' in str(e):
m = MyModel.parse_obj({'value': payload})
else:
raise Prevention
- Always pass a dict (field name -> value) to parse_obj; for ORM objects use from_orm.
- For scalar/list root values, declare a __root__ field.
- Validate payload shape (isinstance(payload, dict)) before calling parse_obj.
When it happens
Trigger: Calling Model.parse_obj(some_int), Model.parse_obj('string'), or parse_obj on a list of non-pair items. For custom-root (__root__) models, _enforce_dict_if_root wraps scalars first, so this fires mainly for non-root models given non-dict input.
Common situations: Passing a JSON-decoded value of the wrong shape, passing an ORM object to parse_obj instead of from_orm, or feeding a scalar where a dict was expected.
Related errors
- validate-by-alias-and-name-false
- bytes_type
- path_type
- Unable to apply constraint '{constraint}' to supplied value
- predicate_failed
AI-assisted analysis of pydantic/pydantic@2e5f0e2b42 (2026-08-04).
Data as JSON: /data/errors/25e43eac8aa72beb.json.
Report an issue: GitHub.