Dataclass Default Factory Is Not Callable: Pass a Constructor or Function
By ON Lab · Sources checked November 9, 2026
default_factory needs a zero-argument callable, not the list it should eventually create. Test that two instances get independent defaults, including any nested mutable data.
Reproduce the boundary in a disposable example
A dataclass field fails because default_factory was given a list value.
from dataclasses import dataclass, field
@dataclass
class Incorrect:
tags: list = field(default_factory=["draft"])
try:
Incorrect()
except TypeError:
pass
else:
raise AssertionError("expected noncallable factory failure")
@dataclass
class Record:
tags: list = field(default_factory=lambda: ["draft"])
notes: list = field(default_factory=list)
a, b = Record(), Record()
a.tags.append("checked")
a.notes.append("local note")
assert a.tags == ["draft", "checked"]
assert b.tags == ["draft"] and b.notes == []
assert a.tags is not b.tags
print("callable factory and independent defaults verified")Read the result before changing application code
The bad declaration stores a list where a callable is expected; the failure appears when the generated initializer needs to invoke it. The good declaration creates the seeded list on demand. Passing list creates an empty list; passing list() has already created a value and therefore crosses the boundary too early.
Choose the behavior your caller needs
Use a named factory function when defaults need several steps or nested containers. Avoid a factory that simply returns one shared module-level list. When callers supply their own list explicitly, decide whether your record borrows it or copies it; default_factory does not automatically isolate caller-provided objects. Verify both default construction and explicit-argument construction in application tests.
Scope and limits
This covers the generated dataclass initializer’s default construction. It does not claim frozen dataclasses deeply freeze their list contents or that a factory validates field types.
Related: compare the adjacent data or execution boundary.
The embedded example was executed in an isolated local Python process on November 9, 2026. It is a reproducible boundary check, not a test of your full application.