django/django · error · InvalidMailer

Could not create 'file_path': {self.file_path} ({err})

Error message

Could not create 'file_path': {self.file_path} ({err})

What it means

The file-based email backend raises this InvalidMailer when os.makedirs(self.file_path, exist_ok=True) fails with an OSError other than FileExistsError — most commonly permission denied, read-only filesystem, or disk full. It indicates the directory at file_path could not be created for an OS-level reason, reported verbatim in the message. This is the MAILERS-enabled code path (alias is not None).

Source

Thrown at django/core/mail/backends/filebased.py:63

            # Make sure that self.file_path is writable.
            if not os.access(self.file_path, os.W_OK):
                raise ImproperlyConfigured(
                    "Could not write to directory: %s" % self.file_path
                )
            return

        if file_path is None:
            raise InvalidMailer("OPTIONS must define 'file_path'.", alias=self.alias)
        self.file_path = os.path.abspath(file_path)
        try:
            os.makedirs(self.file_path, exist_ok=True)
        except FileExistsError:
            raise InvalidMailer(
                f"'file_path' is not a directory: {self.file_path}",
                alias=self.alias,
            )
        except OSError as err:
            raise InvalidMailer(
                f"Could not create 'file_path': {self.file_path} ({err})",
                alias=self.alias,
            )
        if not os.access(self.file_path, os.W_OK):
            raise InvalidMailer(
                f"'file_path' is not writable: {self.file_path}",
                alias=self.alias,
            )

    def write_message(self, message):
        self.stream.write(message.message().as_bytes() + b"\n")
        self.stream.write(b"-" * 79)
        self.stream.write(b"\n")

    def _get_filename(self):
        """Return a unique file name."""
        if self._fname is None:
            timestamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")

View on GitHub (pinned to b5388a3a80)

Solutions

  1. Check the (err) portion of the message for the OS-level cause (PermissionError, OSError, etc.) and resolve that first.
  2. Ensure the parent directory of file_path exists and is writable by the Django process user (mkdir -p and chown).
  3. Point file_path to a location on a writable, persistent volume, especially in containerized deployments.
  4. Run the web/worker process under a user that has write access to the configured file_path.

Example fix

// before
MAILERS = {
    "default": {
        "OPTIONS": {"file_path": "/srv/readonly/emails"}
    }
}
// after
MAILERS = {
    "default": {
        "OPTIONS": {"file_path": "/var/lib/django/emails"}
    }
}
# plus: chown -R appuser:appuser /var/lib/django/emails
Defensive patterns

Strategy: validation

Validate before calling

import os, tempfile
def ensure_writable_parent(path):
    parent = os.path.dirname(os.path.abspath(path))
    if not os.path.isdir(parent):
        try:
            os.makedirs(parent, exist_ok=True)
        except OSError as e:
            raise ImproperlyConfigured(f"Cannot create parent dir for {path}: {e}")
    if not os.access(parent, os.W_OK):
        raise ImproperlyConfigured(f"Parent not writable: {parent}")
    return path

Try / catch

from django.core.mail import InvalidMailer
try:
    conn = mail.mailers['default']
except InvalidMailer as e:
    log.error('Mailer misconfigured: %s', e)
    # fall back to console backend or alert ops

Prevention

When it happens

Trigger: A MAILERS entry using the filebased backend whose OPTIONS 'file_path' points to a location the current process cannot create directories under, e.g. '/root/mail' run as a non-root user, a read-only mount, or a parent directory that does not exist and cannot be auto-created due to permissions. The exception is raised at backend instantiation (when mail.mailers[alias] is first accessed).

Common situations: Running the Django process under a different user than the one owning the target directory; deploying to a read-only filesystem (e.g. some container images) without mounting a writable volume; specifying a relative file_path that resolves to an unexpected absolute location; the parent directory was removed between deploys.

Related errors


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