{"record":{"id":"15b8d282a77a4610","repo":"actualbudget/actual","slug":"backup-zip-file-is-missing-db-sqlite-or-metadata-j","errorCode":null,"errorMessage":"Backup zip file is missing db.sqlite or metadata.json","messagePattern":"Backup zip file is missing db\\.sqlite or metadata\\.json","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/budgetfiles/backups.ts","lineNumber":246,"sourceCode":"      await cloudStorage.upload();\n    } catch {}\n\n    prefs.unloadPrefs();\n\n    const zipContent = await fs.readFile(\n      fs.join(budgetDir, 'backups', backupId),\n      'binary',\n    );\n\n    let entries: Record<string, Uint8Array>;\n    try {\n      entries = safeUnzip(zipContent);\n    } catch (e) {\n      logger.log(e);\n      throw new Error('Error reading backup zip file');\n    }\n    if (!entries['db.sqlite'] || !entries['metadata.json']) {\n      throw new Error('Backup zip file is missing db.sqlite or metadata.json');\n    }\n\n    await fs.writeFile(fs.join(budgetDir, 'db.sqlite'), entries['db.sqlite']);\n    await fs.writeFile(\n      fs.join(budgetDir, 'metadata.json'),\n      entries['metadata.json'],\n    );\n  }\n}\n\nexport function startBackupService(id: string) {\n  if (serviceInterval) {\n    clearInterval(serviceInterval);\n  }\n\n  // Make a backup every 15 minutes\n  serviceInterval = setInterval(\n    async () => {","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/budgetfiles/backups.ts#L228-L264","documentation":"A backup zip must contain both db.sqlite (the budget database) and metadata.json. loadBackup parses the zip successfully but, if either required entry is absent, it throws this error instead of restoring a partial or broken budget.","triggerScenarios":"Calling loadBackup with a zip produced by a different tool or older format that lacks metadata.json, or a user-zipped db.sqlite alone, or an archive that only contains metadata.json (e.g. an export that failed mid-way).","commonSituations":"Hand-rolled backups made by zipping just the db file; third-party scripts that back up only the database; restoring a backup from a much older Actual version with a different archive layout.","solutions":["List the zip contents (unzip -l backup.zip) and confirm both db.sqlite and metadata.json exist at the archive root.","Re-zip the backup including both files, at the top level (no nested folder paths).","Create a fresh backup from a working device (Settings > Backups / export) and restore that instead.","If only db.sqlite exists, import the budget via the file-import flow rather than loadBackup."],"exampleFix":"// before\n// backup.zip contains only 'db.sqlite'\n// after\n// rebuild archive with both entries at root:\n// unzip old.zip db.sqlite && zip backup.zip db.sqlite metadata.json\nawait send('load-backup', { id: backupId });","handlingStrategy":"validation","validationCode":"const zip = await JSZip.loadAsync(zipContent);\nconst ok = zip.file('db.sqlite') && zip.file('metadata.json');\nif (!ok) throw new Error('Backup must contain db.sqlite and metadata.json at the archive root');","typeGuard":"function hasRequiredEntries(entries: Record<string, unknown>): boolean {\n  return Boolean(entries['db.sqlite']) && Boolean(entries['metadata.json']);\n}","tryCatchPattern":"try {\n  await send('load-backup', { id });\n} catch (e) {\n  if (e.message.includes('missing db.sqlite or metadata.json')) {\n    console.error('Incompatible backup layout; re-export or re-zip with both files at root');\n  } else throw e;\n}","preventionTips":["Always create backups through the app's export rather than hand-zipping.","Confirm both files sit at the zip root, not inside a subfolder.","Include metadata.json in any scripted backup of db.sqlite.","Test a restore from each backup archive you keep."],"tags":["backup","zip","schema","restore"],"backgroundTag":"missing-required-file","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}