home-assistant/core · error · InvalidBackupFilename

Invalid filename: {suggested_filename}

Error message

Invalid filename: {suggested_filename}

What it means

Raised by BackupManager._async_receive_backup while validating the uploaded multipart file's filename. suggested_filename defaults to 'backup.tar' when absent; it is sanitized through PureWindowsPath(...).name and rejected if that is empty, differs from the original (meaning it contained path separators like '/' or '\\' or a drive component), or equals '..'. This blocks path-traversal via the upload filename.

Source

Thrown at homeassistant/components/backup/manager.py:1015

        finally:
            self.async_on_backup_event(IdleEvent())

    async def _async_receive_backup(
        self,
        *,
        agent_ids: list[str],
        contents: aiohttp.BodyPartReader,
    ) -> str:
        """Receive and store a backup file from upload."""
        contents.chunk_size = BUF_SIZE
        suggested_filename = contents.filename or "backup.tar"
        safe_filename = PureWindowsPath(suggested_filename).name
        if (
            not safe_filename
            or safe_filename != suggested_filename
            or safe_filename == ".."
        ):
            raise InvalidBackupFilename(f"Invalid filename: {suggested_filename}")
        self.async_on_backup_event(
            ReceiveBackupEvent(
                reason=None,
                stage=ReceiveBackupStage.RECEIVE_FILE,
                state=ReceiveBackupState.IN_PROGRESS,
            )
        )
        written_backup = await self._reader_writer.async_receive_backup(
            agent_ids=agent_ids,
            stream=contents,
            suggested_filename=suggested_filename,
        )
        self.async_on_backup_event(
            ReceiveBackupEvent(
                reason=None,
                stage=ReceiveBackupStage.UPLOAD_TO_AGENTS,
                state=ReceiveBackupState.IN_PROGRESS,
            )

View on GitHub (pinned to 58a3fdb3ea)

Solutions

  1. Send a plain base filename in the multipart Content-Disposition: filename="backup.tar" with no directories or drive letters.
  2. In client code, use Path(filepath).name (or basename) when constructing the multipart field from a full path.
  3. Retry the upload with the corrected filename; nothing else about the request needs to change.

Example fix

# before (python client)
files = {"file": (str(full_path), fh)}  # sends '/home/user/backups/x.tar'

# after
from pathlib import Path
files = {"file": (Path(full_path).name, fh)}  # sends 'x.tar'
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import PurePath

def valid_upload_filename(name: str | None) -> bool:
    if name is None:
        return True  # defaults to backup.tar
    return bool(name) and PurePath(name).name == name and name not in ("..", ".")

Try / catch

from homeassistant.components.backup.manager import InvalidBackupFilename

try:
    backup_id = await manager.async_receive_backup(
        agent_ids=agent_ids, contents=contents
    )
except InvalidBackupFilename as err:
    return web.Response(status=400, text=str(err))

Prevention

When it happens

Trigger: POSTing a multipart upload whose filename field contains 'sub/dir/backup.tar', '..\\..\\evil.tar', 'C:\\backup.tar', is empty-but-not-None, or resolves to '..' after PureWindowsPath normalization.

Common situations: Custom API clients sending full paths as filename; curl/scripts reusing a file path string as filename; deliberately malicious requests probing the upload endpoint.

Related errors


AI-assisted analysis of home-assistant/core@58a3fdb3ea (2026-08-14). Data as JSON: /api/errors/e0bb1c0529471c7e. Report an issue: GitHub.