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

  1. Implement `def start_object(self, obj):` in your subclass to emit whatever per-object framing your format needs.
  2. Subclass a concrete serializer (`django.core.serializers.python.Serializer`) instead of `base.Serializer` so all six hooks are inherited, then override only what differs.
  3. 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

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


AI-assisted analysis of django/django@b5388a3a80 (2026-08-10). Data as JSON: /api/errors/a6e930f229f44905. Report an issue: GitHub.