skip to content

Why does @dataclass raise ValueError for `tags: list = []`, and what is the fix?

level: middleimportance: must knowfreq 66%

answer

  1. The class body runs once
  2. Every instance would share one object
  3. The decorator refuses to build the class
  4. A callable, not a value
  5. field(default_factory=list)

basics

~10 s

A default in the class body is created once and would be shared by every instance, so @dataclass rejects it at class-creation time. Use dataclasses.field(default_factory=list), which calls the factory per instance.

solid answer

~50 s

The default value in a class body is evaluated once, when the class is defined, and the generated `__init__` would assign that one object to every instance — the same trap as a mutable default argument in a plain function. Because that bug is silent and expensive, `@dataclass` refuses to build the class at all and raises `ValueError: mutable default <class 'list'> for field tags is not allowed: use default_factory`. The fix is `tags: list[str] = field(default_factory=list)`: `default_factory` stores a zero-argument callable that the generated `__init__` calls once per instance, so each object gets a fresh list. Since Python 3.11 the check is "is the default hashable?" rather than a hard-coded list/dict/set test, so any unhashable default is rejected — and a mutable-but-hashable custom object still slips through, which the decorator cannot catch for you.

code

python · 11 lines
python
from dataclasses import dataclass, field

@dataclass
class PayrollRow:
    name: str
    deductions: list[str] = field(default_factory=list)

a = PayrollRow("Ada")
b = PayrollRow("Grace")
a.deductions.append("pension")
print(a.deductions, b.deductions)   # ['pension'] []

go deeper

for a junior

Remember the rule of thumb: never write a list, dict or set as a default in a dataclass body. Reach for field(default_factory=list) instead, and know the error message names the fix itself.

for a middle

Explain the mechanics: the class body runs once, so a single default object would be shared by every instance; default_factory takes a zero-argument callable that the generated __init__ calls per construction.

for a senior

Show that you know the check's limit — since 3.11 it rejects unhashable defaults, so a mutable-but-hashable object still slips through and is silently shared. Be able to describe the resulting shared-state bug in production.

for a principal

Own the convention rather than the error: a default that is not an immutable scalar goes through a factory, per-instance timestamps and ids are computed by a factory, and reviewers should not be relying on the interpreter to catch this.

## The bug the check exists to prevent A class body executes once. Whatever you assign there is created once, and the generated `__init__` would hand that single object to every instance: ```python # what the decorator would have to generate def __init__(self, name, tags=[]): # the [] is built once self.tags = tags ``` Every row you construct would then share one list. Consider importing a payroll CSV for an 11-person team, where each row is a small record with a `deductions` list: the first employee's pension entry appends into the shared list, the second row appends into the *same* list, and by the end of the import every one of the 11 records reports all 11 deductions. It is the classic duplicated side effect — nothing raises, the numbers are simply wrong, and it usually surfaces in production as "the totals are too big" long after the import ran. This is exactly the mutable-default-argument trap, moved into a class body. In a plain function Python lets you do it; in a dataclass the decorator has enough information to notice, so it refuses. ## What actually happens ```pycon >>> from dataclasses import dataclass >>> @dataclass ... class Row: ... tags: list = [] ... ValueError: mutable default <class 'list'> for field tags is not allowed: use default_factory ``` Note *when* it happens: at class-creation time, while the decorator runs — not on first instantiation. The module simply fails to import, which is the friendliest possible failure mode. ## The fix: default_factory ```python from dataclasses import dataclass, field @dataclass class PayrollRow: name: str deductions: list[str] = field(default_factory=list) ``` `dataclasses.field()` is not a value — it is a specification object the decorator consumes and replaces. `default_factory` takes a **zero-argument callable**, and the generated `__init__` calls it once per construction when the argument is omitted. Pass the callable itself: `default_factory=list`, not `default_factory=list()`. The latter stores an empty list as the "factory" and blows up at construction with `TypeError: 'list' object is not callable`. Anything zero-argument works: `dict`, `set`, `functools.partial(...)`, a `lambda: {"attempts": 0}`, `uuid.uuid4`, `datetime.datetime.now`. That last pair is the other half of the idiom — a timestamp or an id default must be computed per instance, not frozen at import time, and `field(default_factory=...)` is how you say so. Note also that `default` and `default_factory` are mutually exclusive; supplying both is an error. ## Why a plain function is allowed to do this A regular function may declare `def add(item, items=[])` and Python will not stop it: the default is evaluated once at `def` time and stored on the function object, and the accumulating-list bug is on the author. The dataclass field default is the *same mechanism* — the class-body value becomes the parameter default of the generated `__init__` — but here the decorator sits between you and the signature and has a chance to inspect the value first, so it does. That asymmetry is worth stating in an interview: dataclasses are not applying a different rule about defaults, they are applying the same rule with a guard in front of it. ## What the check actually tests — and its limits Up to Python 3.10 the decorator tested whether the default was an instance of `list`, `dict` or `set`. **Python 3.11 changed the rule to hashability**: a default is rejected when it is unhashable. That is a better proxy for "mutable", and it means a custom class that sets `__hash__ = None` is rejected too: ```pycon >>> class Bag: ... __hash__ = None ... >>> @dataclass ... class Holder: ... b: Bag = Bag() ... ValueError: mutable default <class '__main__.Bag'> for field b is not allowed: use default_factory ``` The important limit is the converse: a **mutable but hashable** object sails straight through. A default that is an instance of an ordinary class — mutable attributes, inherited identity hash — is accepted and then shared by every instance, reproducing the original bug with no error at all. Treat the check as a guard against the three obvious cases, not as a guarantee. The habit that actually protects you is: if the default is not an immutable scalar, `str`, `bytes`, `None`, or a tuple of those, use `default_factory`. ## Related traps worth naming A tuple default is fine and often the cleanest fix for a small constant sequence, because tuples are immutable and hashable. An empty *frozen* set constant is likewise fine. And a factory that closes over shared state — `field(default_factory=lambda: CACHE)` — rebuilds nothing and hands out the same object again; the callable must *create*, not *fetch*. ## Version notes `dataclasses` shipped in Python 3.7 with the list/dict/set check. Python 3.11 generalised it to "unhashable defaults are rejected", which is the behaviour on 3.14. The error message and the `default_factory` remedy have been stable throughout.

  • Why is `field(default_factory=list())` wrong when `field(default_factory=list)` is right?
    `default_factory` must be a zero-argument callable that the generated `__init__` calls per instance. `list` is that callable. `list()` is already an empty list, so it is stored as the factory and calling it fails at construction with `TypeError: 'list' object is not callable`. It is the same distinction as passing a function versus passing its result.
  • Does the mutable-default check catch every shared-default bug?
    No. Since Python 3.11 it rejects unhashable defaults, which covers list, dict, set and any class with `__hash__ = None`. A mutable object that is still hashable — an ordinary class instance using the default identity hash — passes the check and is then shared by every instance. Use `default_factory` for anything that is not an immutable scalar, string, bytes, None or a tuple of those.
  • How would you default a field to the current timestamp or a fresh id?
    With `field(default_factory=...)` and a zero-argument callable such as `datetime.datetime.now` or `uuid.uuid4`. A plain default would be evaluated once at import time, so every instance would carry the same timestamp or id. The factory is called during each construction where the argument is omitted, which is exactly the per-instance semantics you want.

saying these in an interview costs you the question

  • Saying the error only appears on first instantiation
  • Passing default_factory=list() instead of default_factory=list
  • Claiming the check catches every mutable default
  • Using default=[] and copying it in later
  • Thinking default and default_factory can both be given

context