{"record":{"id":"282ef0f9f981c0c5","repo":"Mintplex-Labs/anything-llm","slug":"failed-to-download-file","errorCode":null,"errorMessage":"Failed to download file","messagePattern":"Failed to download file","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"frontend/src/models/files.js","lineNumber":16,"sourceCode":"import { API_BASE } from \"@/utils/constants\";\nimport { baseHeaders } from \"@/utils/request\";\n\nconst StorageFiles = {\n  /**\n   * Download a file from the server\n   * @param {string} filename - The filename to download\n   * @returns {Promise<Blob|null>}\n   */\n  download: async function (storageFilename) {\n    return await fetch(\n      `${API_BASE}/agent-skills/generated-files/${encodeURIComponent(storageFilename)}`,\n      { headers: baseHeaders() }\n    )\n      .then((res) => {\n        if (!res.ok) throw new Error(\"Failed to download file\");\n        return res.blob();\n      })\n      .catch((e) => {\n        console.error(\"Download failed:\", e);\n        return null;\n      });\n  },\n\n  /**\n   * Fetch a generated image as a Blob. The serve endpoint is auth-protected, so\n   * we cannot use the URL directly as an <img> src - callers create an object URL.\n   * @param {string} storageFilename - The image filename to fetch\n   * @returns {Promise<Blob|null>}\n   */\n  image: async function (storageFilename) {\n    return await fetch(\n      `${API_BASE}/image-generation/generated-images/${encodeURIComponent(storageFilename)}`,\n      { headers: baseHeaders() }","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/526360e320da9d1b36074be5ed64fe76e5bbfbbd/frontend/src/models/files.js#L1-L34","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Confirm baseHeaders() sends a non-null Authorization by checking localStorage AUTH_TOKEN before calling.","Open the failing URL in DevTools Network tab and read the response status and body.","Verify storageFilename matches an entry returned by the agent-skills listing endpoint (typo/path traversal is blocked by encodeURIComponent).","Check server logs for the /agent-skills/generated-files route to confirm the file physically exists in its storage root."],"exampleFix":"// before\nconst blob = await StorageFiles.download(name); // null on failure, silent\nif (!blob) return; // no user feedback\n\n// after\nconst blob = await StorageFiles.download(name);\nif (!blob) {\n  showToast(\"File is no longer available.\");\n  return;\n}","handlingStrategy":"validation","validationCode":"function canDownload(storageFilename) {\n  if (typeof storageFilename !== \"string\" || storageFilename.trim() === \"\") return false;\n  if (!window.localStorage.getItem(\"anythingllm_authToken\")) return false;\n  return true;\n}\n// if (!canDownload(name)) skip the call","typeGuard":"/** @param {any} r @returns {r is Blob} */\nfunction isBlob(r) { return r instanceof Blob; }","tryCatchPattern":"// Library already catches and returns null — guard the return value.\nconst blob = await StorageFiles.download(name);\nif (!isBlob(blob)) { /* show 'file unavailable' */ }","preventionTips":["Always encodeURIComponent the filename when building URLs yourself (the lib already does).","Null-check the resolved value before creating an object URL.","Revoke object URLs after use to avoid leaks."],"tags":["network","filesystem","auth","agent-skills"],"backgroundTag":null,"analyzedSha":"526360e320da9d1b36074be5ed64fe76e5bbfbbd","analyzedAt":"2026-08-13T01:45:47.170Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}