{"record":{"id":"51e70db94d2c7144","repo":"django/django","slug":"subclasses-of-storage-must-provide-a-listdir-met","errorCode":null,"errorMessage":"subclasses of Storage must provide a listdir() method","messagePattern":"subclasses of Storage must provide a listdir\\(\\) method","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"django/core/files/storage/base.py","lineNumber":164,"sourceCode":"        raise NotImplementedError(\n            \"subclasses of Storage must provide a delete() method\"\n        )\n\n    def exists(self, name):\n        \"\"\"\n        Return True if a file referenced by the given name already exists in\n        the storage system, or False if the name is available for a new file.\n        \"\"\"\n        raise NotImplementedError(\n            \"subclasses of Storage must provide an exists() method\"\n        )\n\n    def listdir(self, path):\n        \"\"\"\n        List the contents of the specified path. Return a 2-tuple of lists:\n        the first item being directories, the second item being files.\n        \"\"\"\n        raise NotImplementedError(\n            \"subclasses of Storage must provide a listdir() method\"\n        )\n\n    def size(self, name):\n        \"\"\"\n        Return the total size, in bytes, of the file specified by name.\n        \"\"\"\n        raise NotImplementedError(\"subclasses of Storage must provide a size() method\")\n\n    def url(self, name):\n        \"\"\"\n        Return an absolute URL where the file's contents can be accessed\n        directly by a web browser.\n        \"\"\"\n        raise NotImplementedError(\"subclasses of Storage must provide a url() method\")\n\n    def get_accessed_time(self, name):\n        \"\"\"","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/django/django/blob/b5388a3a80cafcce2e34196d8e81cf5b48eb33bb/django/core/files/storage/base.py#L146-L182","documentation":"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.","triggerScenarios":"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.","commonSituations":"Custom object-storage backend without a listdir implementation; code using storage.listdir() for cleanup or reporting; static-files tooling that enumerates a custom storage.","solutions":["Implement listdir(self, path) in the custom Storage subclass, mapping the backend's list operation to the (dirs, files) tuple.","Subclass an existing backend (FileSystemStorage) that implements listdir.","Avoid calling storage.listdir() on remote backends; use backend-specific listing APIs directly.","Document which storage methods are required before building a custom backend."],"exampleFix":"# before\nclass MyStorage(Storage):\n    ...\n# after\nclass MyStorage(Storage):\n    def listdir(self, path):\n        dirs, files = [], []\n        for entry in self.client.list(path):\n            (dirs if entry.is_dir else files).append(entry.name)\n        return dirs, files","handlingStrategy":"type-guard","validationCode":"def storage_can_listdir(storage) -> bool:\n    return 'listdir' in storage.__class__.__dict__","typeGuard":"def implements_listdir(storage) -> bool:\n    return any('listdir' in c.__dict__ for c in storage.__class__.__mro__)","tryCatchPattern":"try:\n    dirs, files = storage.listdir(path)\nexcept NotImplementedError:\n    files = []  # fallback to backend-specific listing API","preventionTips":["Implement listdir(self, path) -> (dirs, files) in custom backends.","Avoid storage.listdir() on remote backends; use native listing.","Document required methods before building a custom storage."],"tags":["django","storage","not-implemented","subclass","listdir"],"backgroundTag":null,"analyzedSha":"b5388a3a80cafcce2e34196d8e81cf5b48eb33bb","analyzedAt":"2026-08-10T17:37:52.993Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}