Skip to content

fix(desktop): restore correct filename in save dialog for attachment downloads#4296

Open
niklaskie wants to merge 2 commits into
multica-ai:mainfrom
niklaskie:fix/desktop-download-filename
Open

fix(desktop): restore correct filename in save dialog for attachment downloads#4296
niklaskie wants to merge 2 commits into
multica-ai:mainfrom
niklaskie:fix/desktop-download-filename

Conversation

@niklaskie

Copy link
Copy Markdown

Problem

Closes #4153

When downloading an attachment from the desktop app, the native save dialog always shows download.txt as the filename — regardless of the actual file type or name.

Root cause: win.webContents.downloadURL() is called without a will-download session handler. Without this handler, Electron derives the suggested filename from the URL path (/api/attachments/<id>/downloaddownload.txt) and ignores the Content-Disposition header sent by the server.

This does not affect the browser (web) version, which handles Content-Disposition natively and works correctly.

Fix

Add a will-download event listener on window.webContents.session that reads the correct filename via item.getFilename() (which parses Content-Disposition) and passes it to setSaveDialogOptions. The user still gets the native save dialog — just with the correct default filename and extension.

Testing

  • Self-hosted deployment, LocalStorage storage mode, desktop app 0.3.24
  • Before: save dialog shows download.txt for all attachment types
  • After: save dialog shows the correct filename (e.g. IKS Logo Red.png, IKS RGB.ai)

…downloads

Without a will-download handler, Electron derives the suggested filename
from the URL path (/api/attachments/<id>/download → download.txt) and
ignores the Content-Disposition header sent by the server.

Adding the handler and forwarding item.getFilename() — which reads the
Content-Disposition filename — restores the correct name and extension
in the native save dialog.

Fixes multica-ai#4153
@vercel

vercel Bot commented Jun 18, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the IndexLabs Team on Vercel.

A member of the Team first needs to authorize it.

@multica-eve multica-eve left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tracking this down and sending the focused fix. The product behavior you are fixing is the right one: desktop downloads should suggest the attachment's real filename instead of download.txt, and your use of item.getFilename() is the right mechanism for getting the filename Electron parsed from Content-Disposition.

I need one change before we can merge this:

The new will-download listener is registered inside createWindow(), but window.webContents.session is a shared session. On macOS, app.on("activate") can call createWindow() again after all windows have been closed. Each recreated window would add another listener to the same shared session, so later downloads can trigger multiple handlers and eventually cause listener leaks / MaxListenersWarning.

Please move this to a one-time app/session setup, or guard it so each session only gets the handler once. For example, a module-level guard or WeakSet<Electron.Session> would work:

const downloadDialogSessions = new WeakSet<Electron.Session>();

function installDownloadSaveDialogHandler(window: BrowserWindow): void {
  const { session } = window.webContents;
  if (downloadDialogSessions.has(session)) return;
  downloadDialogSessions.add(session);

  session.on("will-download", (_event, item) => {
    item.setSaveDialogOptions({
      defaultPath: join(app.getPath("downloads"), item.getFilename()),
    });
  });
}

After that, please also verify the close-window / reopen-window path: close all desktop windows, reopen the app, then download an attachment and confirm the save dialog still shows the correct filename without registering duplicate handlers.

…tration

On macOS, app activate can call createWindow() again after all windows
are closed. window.webContents.session is shared, so registering the
will-download handler inside createWindow() would add duplicate listeners.

Extract into installDownloadSaveDialogHandler() with a WeakSet guard so
the handler is registered at most once per session.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Attachment download endpoint missing Content-Disposition header — browser saves file as 'download.txt'

2 participants