django/django · error · NotImplementedError

subclasses of Storage must provide a listdir() method

Error message

subclasses of Storage must provide a listdir() method

What it means

Raised as NotImplementedError by the base Storage.listdir() abstract method. Subclasses must implement listdir(self, path) returning a 2-tuple of (directories, files) lists. The base raises at storage/base.py:164.

Source

Thrown at django/core/files/storage/base.py:164

        raise NotImplementedError(
            "subclasses of Storage must provide a delete() method"
        )

    def exists(self, name):
        """
        Return True if a file referenced by the given name already exists in
        the storage system, or False if the name is available for a new file.
        """
        raise NotImplementedError(
            "subclasses of Storage must provide an exists() method"
        )

    def listdir(self, path):
        """
        List the contents of the specified path. Return a 2-tuple of lists:
        the first item being directories, the second item being files.
        """
        raise NotImplementedError(
            "subclasses of Storage must provide a listdir() method"
        )

    def size(self, name):
        """
        Return the total size, in bytes, of the file specified by name.
        """
        raise NotImplementedError("subclasses of Storage must provide a size() method")

    def url(self, name):
        """
        Return an absolute URL where the file's contents can be accessed
        directly by a web browser.
        """
        raise NotImplementedError("subclasses of Storage must provide a url() method")

    def get_accessed_time(self, name):
        """

View on GitHub (pinned to b5388a3a80)

Solutions

  1. Implement listdir(self, path) in the custom Storage subclass, mapping the backend's list operation to the (dirs, files) tuple.
  2. Subclass an existing backend (FileSystemStorage) that implements listdir.
  3. Avoid calling storage.listdir() on remote backends; use backend-specific listing APIs directly.
  4. Document which storage methods are required before building a custom backend.

Example fix

# before
class MyStorage(Storage):
    ...
# after
class MyStorage(Storage):
    def listdir(self, path):
        dirs, files = [], []
        for entry in self.client.list(path):
            (dirs if entry.is_dir else files).append(entry.name)
        return dirs, files
Defensive patterns

Strategy: type-guard

Validate before calling

def storage_can_listdir(storage) -> bool:
    return 'listdir' in storage.__class__.__dict__

Type guard

def implements_listdir(storage) -> bool:
    return any('listdir' in c.__dict__ for c in storage.__class__.__mro__)

Try / catch

try:
    dirs, files = storage.listdir(path)
except NotImplementedError:
    files = []  # fallback to backend-specific listing API

Prevention

When it happens

Trigger: Calling storage.listdir(path) on a Storage subclass that does not override listdir(). Commonly hit via admin 'collectstatic --list', static-files finders, or custom management commands that enumerate stored files.

Common situations: Custom object-storage backend without a listdir implementation; code using storage.listdir() for cleanup or reporting; static-files tooling that enumerates a custom storage.

Related errors


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