jitsi/jitsi-meet · warning

Could not download file:

Error message

Could not download file:

What it means

A logger.warn in the file-sharing web middleware: downloading a shared file via its presigned URL failed. The promise chain from the download attempt (fetch/save of the presigned URL) rejects, the catch logs 'Could not download file:' with the underlying error, and a sticky 'download failed' notification is dispatched.

Source

Thrown at react/features/file-sharing/middleware.web.ts:248

                'Authorization': `Bearer ${token}`
            }
        }))
        .then((response: any) => response.json())
        .then((data: { fileName: string; presignedUrl: string; }) => {
            const { presignedUrl, fileName } = data;

            if (!presignedUrl) {
                throw new Error('No presigned URL found in the response.');
            }

            store.dispatch(showNotification({
                titleKey: 'fileSharing.downloadStarted'
            }, NOTIFICATION_TIMEOUT_TYPE.SHORT));

            return downloadFile(presignedUrl, fileName);
        })
        .catch((error: any) => {
            logger.warn('Could not download file:', error);

            store.dispatch(showErrorNotification({
                titleKey: 'fileSharing.downloadFailedTitle',
                descriptionKey: 'fileSharing.downloadFailedDescription',
                appearance: NOTIFICATION_TYPE.ERROR
            }, NOTIFICATION_TIMEOUT_TYPE.STICKY));
        });

        return next(action);
    }

    case _FILE_REMOVED: {
        const result = next(action);
        const state = store.getState();
        const { messages } = state['features/chat'];

        // Find the message corresponding to this file and mark it as deleted.
        const fileMessage = messages.find(msg => msg.messageId === action.fileId);

View on GitHub (pinned to 98de6219cc)

Solutions

  1. Check the logged error object: 403 signature/expiry means expired presigned URL — re-request a fresh URL from the file-sharing backend and retry; network/CORS errors point to storage config
  2. Verify CORS configuration on the file storage allows GET from the deployment origin
  3. Confirm the file still exists server-side and the sharing service issues URLs with adequate TTL
  4. Add a retry with a freshly minted presigned URL before surfacing the sticky failure notification

Example fix

// before
return downloadFile(presignedUrl, fileName);

// after
return downloadFile(presignedUrl, fileName).catch(async error => {
    logger.warn('Could not download file:', error);
    if (error?.status === 403 || error?.name === 'AbortError') {
        const fresh = await fetchNewPresignedUrl(fileUrl); // backend re-sign
        return downloadFile(fresh, fileName);
    }
    throw error;
});
Defensive patterns

Strategy: retry

Validate before calling

// Check URL freshness before downloading (presigned URLs carry Expires param)
const isFresh = (url: string): boolean => {
    const expires = new URL(url).searchParams.get('Expires');
    return !expires || Number(expires) * 1000 > Date.now() + 30_000;
};
if (!isFresh(presignedUrl)) {
    presignedUrl = await refreshPresignedUrl(fileName);
}

Type guard

const isDownloadError = (e: unknown): e is { status: number; message: string } =>
    typeof e === 'object' && e !== null && 'status' in e;

Try / catch

.catch((error: unknown) => {
    logger.warn('Could not download file:', error);
    if (isDownloadError(error) && (error.status === 403 || error.status === 410)) {
        return refreshAndRetryDownload(fileName); // get fresh presigned URL
    }
    store.dispatch(showErrorNotification({
        titleKey: 'fileSharing.downloadFailedTitle',
        descriptionKey: 'fileSharing.downloadFailedDescription'
    }, NOTIFICATION_TIMEOUT_TYPE.STICKY));
})

Prevention

When it happens

Trigger: The presigned URL is expired or revoked (S3/URL TTL passed), the storage backend is unreachable, CORS blocks the GET from the browser, the file was deleted server-side, or a network failure/abort occurs during fetch.

Common situations: User clicks a share link long after upload and the presigned URL expired; file-sharing storage (S3/other) misconfigured or bucket deleted; missing CORS headers on the object store; reverse proxy timeouts on large files; flaky client network.


AI-assisted analysis of jitsi/jitsi-meet@98de6219cc (2026-08-28). Data as JSON: /api/errors/e4ba95762d7f1386. Report an issue: GitHub.