django/django · error · NotImplementedError
subclasses of Serializer must provide a start_object() metho
Error message
subclasses of Serializer must provide a start_object() method
What it means
`Serializer.start_object()` is an abstract hook in Django's serializer template-method framework (django/core/serializers/base.py:166). It is invoked once per object at the start of serialization (base.py:110); the base class raises NotImplementedError to force subclasses to provide concrete behavior. Hitting it means a custom Serializer subclass did not override this required method.
Source
Thrown at django/core/serializers/base.py:170
def start_serialization(self):
"""
Called when serializing of the queryset starts.
"""
raise NotImplementedError(
"subclasses of Serializer must provide a start_serialization() method"
)
def end_serialization(self):
"""
Called when serializing of the queryset ends.
"""
pass
def start_object(self, obj):
"""
Called when serializing of an object starts.
"""
raise NotImplementedError(
"subclasses of Serializer must provide a start_object() method"
)
def end_object(self, obj):
"""
Called when serializing of an object ends.
"""
pass
def handle_field(self, obj, field):
"""
Called to handle each individual (non-relational) field on an object.
"""
raise NotImplementedError(
"subclasses of Serializer must provide a handle_field() method"
)
def handle_fk_field(self, obj, field):View on GitHub (pinned to b5388a3a80)
Solutions
- Implement `def start_object(self, obj):` in your subclass to emit whatever per-object framing your format needs.
- Subclass a concrete serializer (`django.core.serializers.python.Serializer`) instead of `base.Serializer` so all six hooks are inherited, then override only what differs.
- Verify all six required hooks exist: `start_serialization`, `start_object`, `end_object`, `handle_field`, `handle_fk_field`, `handle_m2m_field`.
Example fix
// before
class CsvSerializer(base.Serializer):
def start_serialization(self):
self.stream.write('model,pk,field,value\n')
# missing start_object -> NotImplementedError at base.py:170
// after
class CsvSerializer(base.Serializer):
def start_serialization(self):
self.stream.write('model,pk,field,value\n')
def start_object(self, obj):
self._current_obj = obj
def end_object(self, obj):
self._current_obj = None Defensive patterns
Strategy: validation
Validate before calling
from django.core.serializers.base import Serializer
REQUIRED = ('start_serialization', 'start_object', 'end_object',
'handle_field', 'handle_fk_field', 'handle_m2m_field')
missing = [m for m in REQUIRED if not callable(getattr(MySerializer, m, None))]
assert not missing, f'MySerializer missing overrides: {missing}' Type guard
def is_complete_serializer(cls) -> bool:
return (issubclass(cls, Serializer) and
all(callable(getattr(cls, m, None))
for m in ('start_object', 'handle_field',
'handle_fk_field', 'handle_m2m_field'))) Prevention
- Subclass python.Serializer (which implements all hooks) and override only what you need.
- Add a smoke test that serializes a model exercising plain, FK, and M2M fields.
- Lint for NotImplementedError-raising base methods when authoring a subclass.
When it happens
Trigger: Calling `my_serializer.serialize(queryset)` on an instance of a class that subclasses `django.core.serializers.base.Serializer` directly (not PythonSerializer) and omits a `start_object(self, obj)` definition. The NotImplementedError fires on the first object in the queryset before any field is processed.
Common situations: Writing a custom serializer backend for a new format (CSV, MessagePack, XML variants) and forgetting one of the six required hooks; copy-pasting an existing serializer and deleting methods; upgrading Django and refactoring a third-party serializer (e.g. django-rest-framework's serializer bridge) that dropped the override.
Related errors
- subclasses of Serializer must provide a handle_field() metho
- subclasses of Serializer must provide a handle_fk_field() me
- subclasses of Serializer must provide a handle_m2m_field() m
- GEOSCoordSeq with an M dimension requires GEOS 3.14+.
- subclasses of BaseStorage must provide a _get() method
AI-assisted analysis of django/django@b5388a3a80 (2026-08-10).
Data as JSON: /api/errors/a6e930f229f44905.
Report an issue: GitHub.