{"record":{"id":"30f2699e16a2e98f","repo":"linshenkx/prompt-optimizer","slug":"favorites-package-is-missing-favorites-json","errorCode":null,"errorMessage":"favorites package is missing favorites.json","messagePattern":"favorites package is missing favorites\\.json","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/ui/src/utils/favorite-resource-package.ts","lineNumber":229,"sourceCode":"}\n\nexport const readFavoriteResourcePackage = (\n  input: ArrayBuffer | Uint8Array,\n): {\n  manifest: FavoriteResourcePackageManifest\n  favoritesJson: string\n  files: Record<string, Uint8Array>\n} => {\n  const bytes = input instanceof Uint8Array ? input : new Uint8Array(input)\n  const files = unzipSync(bytes)\n  const manifestBytes = files[MANIFEST_JSON_PATH]\n  const favoritesBytes = files[FAVORITES_JSON_PATH]\n\n  if (!manifestBytes) {\n    throw new Error('favorites package is missing manifest.json')\n  }\n  if (!favoritesBytes) {\n    throw new Error('favorites package is missing favorites.json')\n  }\n\n  return {\n    manifest: parseManifest(strFromU8(manifestBytes)),\n    favoritesJson: strFromU8(favoritesBytes),\n    files,\n  }\n}\n\nconst restoreFavoritePackageResources = async (\n  manifest: FavoriteResourcePackageManifest,\n  files: Record<string, Uint8Array>,\n  imageStorageService: ImportFavoriteResourcePackageOptions['imageStorageService'],\n): Promise<FavoriteResourceRestoreReport> => {\n  const report: FavoriteResourceRestoreReport = {\n    restored: 0,\n    skipped: 0,\n    missing: [...manifest.missingResourceIds],","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/linshenkx/prompt-optimizer/blob/3e677b1d9f7e0493c142c175560531e7ae786dce/packages/ui/src/utils/favorite-resource-package.ts#L211-L247","documentation":"Thrown by readFavoriteResourcePackage in packages/ui/src/utils/favorite-resource-package.ts when the zip contains manifest.json but no entry at FAVORITES_JSON_PATH ('favorites.json'). The favorites payload is required alongside the manifest, so the package is rejected. This is the second and last entry-presence check before parseManifest runs on the manifest bytes.","triggerScenarios":"A zip with manifest.json but without a root-level favorites.json entry: partial/interrupted export, manual removal or renaming of the payload, or a manifest-only template archive passed to the reader.","commonSituations":"Interrupted exports producing incomplete archives; users pruning files from the zip; repackaging pipelines that drop JSON payloads; casing differences from zip tools on case-sensitive systems.","solutions":["Confirm 'favorites.json' exists at the zip root next to manifest.json","Re-export the favorites package from the source app to get a complete archive","Pre-check required entries before calling readFavoriteResourcePackage","If assembling packages programmatically, always write both manifest.json and favorites.json"],"exampleFix":"// before\nconst pkg = readFavoriteResourcePackage(bytes) // throws: missing favorites.json\n\n// after\nconst names = Object.keys(unzipSync(bytes))\nfor (const required of ['manifest.json', 'favorites.json']) {\n  if (!names.includes(required)) throw new Error(`Package incomplete: no ${required}`)\n}\nconst pkg = readFavoriteResourcePackage(bytes)","handlingStrategy":"validation","validationCode":"import { unzipSync } from 'fflate'\n\nconst hasFavoritePayload = (bytes: Uint8Array): boolean => {\n  try {\n    const entries = Object.keys(unzipSync(bytes))\n    return entries.includes('manifest.json') && entries.includes('favorites.json')\n  } catch {\n    return false\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  const pkg = readFavoriteResourcePackage(bytes)\n} catch (e) {\n  if (e instanceof Error && e.message.includes('missing favorites.json')) {\n    // incomplete package: re-export rather than restore\n    return\n  }\n  throw e\n}","preventionTips":["Always write both manifest.json and favorites.json when creating packages","Pre-validate required entries before calling the reader","Re-export instead of repairing partial archives","Check entry casing when zipping on case-sensitive systems"],"tags":["zip","missing-file","favorites","partial-export"],"backgroundTag":"zip-missing-entry","analyzedSha":"3e677b1d9f7e0493c142c175560531e7ae786dce","analyzedAt":"2026-08-27T21:29:16.709Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}