pola-rs/polars · error · ValueError
expected list or dict of objects
Error message
expected list or dict of objects
What it means
Raised by polars.json_normalize when `data` is not a Mapping, not a non-str Iterable/Sequence, or is a bare string. The function flattens semi-structured JSON objects, so it accepts a dict (single record), a list of dicts, or any non-string iterable of records; scalars, strings, None, and bytes all fall to the else branch and raise.
Source
Thrown at py-polars/src/polars/convert/normalize.py:246
╞══════╪════════════╪═══════════════════════════════╡
│ 1 ┆ Cole Volk ┆ b"{"height":180,"weight":85}" │
│ 2 ┆ Faye Raker ┆ b"{"height":155,"weight":58}" │
│ null ┆ Mark Reg ┆ b"{"height":170,"weight":78}" │
└──────┴────────────┴───────────────────────────────┘
"""
if max_level is None:
max_level = 1 << 32 # eg: u32
max_level += 1
if isinstance(data, Sequence) and len(data) == 0:
return DataFrame(schema=schema)
elif isinstance(data, Mapping):
data = [data]
elif isinstance(data, Iterable) and not isinstance(data, str): # type: ignore[redundant-expr]
data = list(data)
else:
msg = "expected list or dict of objects"
raise ValueError(msg)
if encoder is None:
encoder = json.dumps
return DataFrame(
_simple_json_normalize(
data,
separator=separator,
max_level=max_level,
encoder=encoder,
),
schema=schema,
strict=strict,
infer_schema_length=infer_schema_length,
)
View on GitHub (pinned to df599052da)
Solutions
- Parse the text first: pl.json_normalize(json.loads(text)) or json_normalize(response.json())
- For a single object, pass the dict itself or wrap it in a list
- For JSONL/ndjson, parse per line: pl.json_normalize([json.loads(line) for line in text.splitlines()])
- For whole-file JSON, prefer pl.read_json(path) which handles structure directly
Example fix
# before
pl.json_normalize('{"a": 1, "b": {"c": 2}}')
# after
import json
pl.json_normalize(json.loads('{"a": 1, "b": {"c": 2}}')) Defensive patterns
Strategy: type-guard
Validate before calling
from collections.abc import Mapping
def normalize_input(data):
import json
if isinstance(data, str):
data = json.loads(data)
if isinstance(data, Mapping):
data = [data]
return list(data) # ready for pl.json_normalize Type guard
from collections.abc import Mapping, Iterable
from typing import TypeGuard
def is_json_normalizable(data: object) -> TypeGuard[Mapping | list[Mapping]]:
return isinstance(data, Mapping) or (
isinstance(data, Iterable) and not isinstance(data, (str, bytes))
) Prevention
- Always json.loads() response bodies before json_normalize
- Wrap single JSON objects in a list for uniform handling
- For whole files use pl.read_json rather than manual normalize
When it happens
Trigger: pl.json_normalize('{"a": 1}') with a raw JSON string instead of parsed objects; pl.json_normalize(5), pl.json_normalize(None), or pl.json_normalize(b'...'); passing a single non-dict scalar or a str column value.
Common situations: Reading an API response body and forgetting json.loads / response.json(); handling a JSON column where one row is a plain string; feeding the whole text of a JSONL file rather than iterating parsed lines.
Related errors
- unexpected time zone offset: {offset!r}
- expected `other` to be a {qualified_type_name(current)!r}, n
- expected pandas DataFrame or Series, got {qualified_type_nam
- input string does not contain DataFrame or Series
- DataFrame constructor called with unsupported type {type(dat
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/39139d10e804bb07.
Report an issue: GitHub.