Mintplex-Labs/anything-llm · warning · Error

Failed to download file

Error message

Failed to download file

What it means

Thrown by StorageFiles.download when the GET to /api/agent-skills/generated-files/{storageFilename} returns a non-2xx status. The request carries a Bearer token from localStorage via baseHeaders(), so a missing/expired token yields 401/403 and trips this guard. The .catch() swallows it and the function resolves to null, so the caller observes a missing download rather than a thrown exception.

Source

Thrown at frontend/src/models/files.js:16

import { API_BASE } from "@/utils/constants";
import { baseHeaders } from "@/utils/request";

const StorageFiles = {
  /**
   * Download a file from the server
   * @param {string} filename - The filename to download
   * @returns {Promise<Blob|null>}
   */
  download: async function (storageFilename) {
    return await fetch(
      `${API_BASE}/agent-skills/generated-files/${encodeURIComponent(storageFilename)}`,
      { headers: baseHeaders() }
    )
      .then((res) => {
        if (!res.ok) throw new Error("Failed to download file");
        return res.blob();
      })
      .catch((e) => {
        console.error("Download failed:", e);
        return null;
      });
  },

  /**
   * Fetch a generated image as a Blob. The serve endpoint is auth-protected, so
   * we cannot use the URL directly as an <img> src - callers create an object URL.
   * @param {string} storageFilename - The image filename to fetch
   * @returns {Promise<Blob|null>}
   */
  image: async function (storageFilename) {
    return await fetch(
      `${API_BASE}/image-generation/generated-images/${encodeURIComponent(storageFilename)}`,
      { headers: baseHeaders() }

View on GitHub (pinned to 526360e320)

Solutions

  1. Confirm baseHeaders() sends a non-null Authorization by checking localStorage AUTH_TOKEN before calling.
  2. Open the failing URL in DevTools Network tab and read the response status and body.
  3. Verify storageFilename matches an entry returned by the agent-skills listing endpoint (typo/path traversal is blocked by encodeURIComponent).
  4. Check server logs for the /agent-skills/generated-files route to confirm the file physically exists in its storage root.

Example fix

// before
const blob = await StorageFiles.download(name); // null on failure, silent
if (!blob) return; // no user feedback

// after
const blob = await StorageFiles.download(name);
if (!blob) {
  showToast("File is no longer available.");
  return;
}
Defensive patterns

Strategy: validation

Validate before calling

function canDownload(storageFilename) {
  if (typeof storageFilename !== "string" || storageFilename.trim() === "") return false;
  if (!window.localStorage.getItem("anythingllm_authToken")) return false;
  return true;
}
// if (!canDownload(name)) skip the call

Type guard

/** @param {any} r @returns {r is Blob} */
function isBlob(r) { return r instanceof Blob; }

Try / catch

// Library already catches and returns null — guard the return value.
const blob = await StorageFiles.download(name);
if (!isBlob(blob)) { /* show 'file unavailable' */ }

Prevention

When it happens

Trigger: Calling StorageFiles.download("report.pdf") when storageFilename does not exist on disk (404), when localStorage AUTH_TOKEN is absent or expired (401/403), when the agent-skills storage path is misconfigured on the server, or when the generated file was garbage-collected from a non-persistent volume.

Common situations: The agent skill that produced the file ran in a different container/instance than the one serving downloads; the file was written to ephemeral storage and lost on redeploy; the user clicked a stale download link from a previous session after their token expired.

Related errors


AI-assisted analysis of Mintplex-Labs/anything-llm@526360e320 (2026-08-13). Data as JSON: /api/errors/282ef0f9f981c0c5. Report an issue: GitHub.