{"record":{"id":"2f62d8cebb900c59","repo":"Stirling-Tools/Stirling-PDF","slug":"no-valid-files-found-in-storage-for-zip-download","errorCode":null,"errorMessage":"No valid files found in storage for ZIP download","messagePattern":"No valid files found in storage for ZIP download","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/editor/src/core/utils/downloadUtils.ts","lineNumber":78,"sourceCode":"): Promise<void> {\n  if (files.length === 0) {\n    throw new Error(\"No files provided for ZIP download\");\n  }\n\n  // Convert stored files to File objects (tracking ids so export policies can\n  // version the in-editor file).\n  const filesToZip: File[] = [];\n  const fileIds: (string | undefined)[] = [];\n  for (const fileWithUrl of files) {\n    const stirlingFile = await fileStorage.getStirlingFile(fileWithUrl.id);\n    if (stirlingFile) {\n      filesToZip.push(stirlingFile);\n      fileIds.push(fileWithUrl.id);\n    }\n  }\n\n  if (filesToZip.length === 0) {\n    throw new Error(\"No valid files found in storage for ZIP download\");\n  }\n\n  // Enforce any export-triggered policy on each PDF before they're zipped.\n  const enforced = await enforceExportPolicies(filesToZip, fileIds);\n\n  // Generate default filename if not provided\n  const finalZipFilename =\n    zipFilename ||\n    `files-${new Date().toISOString().slice(0, 19).replace(/[:-]/g, \"\")}.zip`;\n\n  // Create and download ZIP\n  const { zipFile } = await zipFileService.createZipFromFiles(\n    enforced,\n    finalZipFilename,\n  );\n  await downloadFile({ data: zipFile, filename: finalZipFilename });\n}\n","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/Stirling-Tools/Stirling-PDF/blob/9ef20dcab80b85041912f045e17a6aea1d08f969/frontend/editor/src/core/utils/downloadUtils.ts#L60-L96","documentation":"Thrown by downloadFilesAsZip when, after iterating all requested files and looking each up in IndexedDB, zero files were successfully retrieved. Unlike error 70 (single file), this aggregates across the whole batch and fires only when every single lookup failed, meaning there is nothing to put in the ZIP. The function fails fast rather than creating an empty archive.","triggerScenarios":"Calling downloadFilesAsZip(files) where every file.id returns null from fileStorage.getStirlingFile. This is the batch equivalent of error 70 occurring for 100% of the input.","commonSituations":"All files in the selection were evicted from the LRU cache or cleared from storage. The FileContext holds stale references to files that were never persisted or have since been removed. A bulk 'download all' action was triggered after a storage wipe.","solutions":["Check each file's presence in storage before enabling the ZIP download button; disable it if none survive.","Re-run the operations or re-upload the source files to repopulate storage.","Surface a user-facing message listing which files are missing rather than a generic error.","Increase storage retention limits if the entire set is being evicted."],"exampleFix":"// before\nawait downloadFilesAsZip(files); // throws if all evicted\n// after\nconst available = [];\nfor (const f of files) { if (await fileStorage.getStirlingFile(f.id)) available.push(f); }\nif (available.length === 0) { notify('No files are available to download.'); return; }\nawait downloadFilesAsZip(available);","handlingStrategy":"validation","validationCode":"import { fileStorage } from '@app/services/fileStorage';\n\nasync function filterAvailableFiles(files: StirlingFileStub[]): Promise<StirlingFileStub[]> {\n  const available: StirlingFileStub[] = [];\n  for (const f of files) {\n    if (await fileStorage.getStirlingFile(f.id)) available.push(f);\n  }\n  return available;\n}\n\nconst available = await filterAvailableFiles(files);\nif (available.length === 0) {\n  showUser('None of the selected files are available in storage.');\n  return;\n}","typeGuard":"async function availableFileCount(files: StirlingFileStub[]): Promise<number> {\n  let n = 0;\n  for (const f of files) if (await fileStorage.getStirlingFile(f.id)) n++;\n  return n;\n}","tryCatchPattern":"try {\n  await downloadFilesAsZip(files);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('No valid files')) {\n    showUser('No files are available to download. They may have been cleared from storage.');\n  } else { throw e; }\n}","preventionTips":["Pre-filter files by storage availability before offering ZIP download.","Disable the ZIP button when no files are available.","Increase storage retention to avoid mass eviction.","Show per-file availability status so users know which files are missing."],"tags":["download","indexeddb","storage","zip","file-not-found"],"backgroundTag":null,"analyzedSha":"9ef20dcab80b85041912f045e17a6aea1d08f969","analyzedAt":"2026-08-13T22:11:39.827Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}