{"record":{"id":"e1c4cb8bcc050a60","repo":"actualbudget/actual","slug":"cannot-delete-the-last-dashboard-page","errorCode":null,"errorMessage":"Cannot delete the last dashboard page","messagePattern":"Cannot delete the last dashboard page","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/dashboard/app.ts","lineNumber":122,"sourceCode":"      }\n    });\n  },\n};\n\nasync function createDashboardPage({ name }: { name: string }) {\n  const id = uuidv4();\n  await db.insertWithSchema('dashboard_pages', { id, name });\n\n  return id;\n}\n\nasync function deleteDashboardPage(id: string) {\n  const res = await db.first<{ c: number }>(\n    'SELECT count(*) as c FROM dashboard_pages WHERE tombstone = 0',\n  );\n\n  if ((res?.c ?? 0) <= 1) {\n    throw new Error('Cannot delete the last dashboard page');\n  }\n\n  const deleting_widgets = await db.all<Pick<db.DbDashboard, 'id'>>(\n    'SELECT id FROM dashboard WHERE dashboard_page_id = ? AND tombstone = 0',\n    [id],\n  );\n\n  await batchMessages(async () => {\n    await db.delete_('dashboard_pages', id);\n    // Tombstone all widgets for this dashboard\n    await Promise.all(\n      deleting_widgets.map(({ id }) => db.delete_('dashboard', id)),\n    );\n  });\n}\n\nasync function renameDashboardPage({ id, name }: { id: string; name: string }) {\n  await db.updateWithSchema('dashboard_pages', { id, name });","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/dashboard/app.ts#L104-L140","documentation":"deleteDashboardPage refuses to delete a dashboard page when fewer than 2 non-tombstoned pages exist. Actual requires at least one dashboard page to remain, so deleting the last one is blocked with this plain Error.","triggerScenarios":"Calling the deleteDashboardPage handler (e.g. via 'dashboard-page-delete' from the UI or API) when the dashboard_pages table has exactly one row with tombstone = 0.","commonSituations":"Users or scripts cleaning up dashboard pages who don't realize the final default page cannot be removed; automated cleanup that deletes pages one by one until only one remains and then tries to delete it.","solutions":["Create another dashboard page first (dashboard-page-create), then delete the unwanted page.","Keep the last page and clear its widgets instead of deleting the page itself.","Catch the error in UI/script code and treat 'last page' as a no-op."],"exampleFix":"// before\nawait runMutator(() => deleteDashboardPage(pageId));\n// after\nconst pages = await getDashboardPages();\nif (pages.length > 1) {\n  await runMutator(() => deleteDashboardPage(pageId));\n}","handlingStrategy":"try-catch","validationCode":"const pages = await send('dashboard-get-pages');\nif (pages.length <= 1) {\n  throw new Error('Refusing to delete the last dashboard page');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await send('dashboard-delete-page', { id });\n} catch (e) {\n  if (e.message === 'Cannot delete the last dashboard page') {\n    console.warn('Keep at least one dashboard page; create a new page first.');\n  }\n}","preventionTips":["Check the page count before batch-deleting pages and stop at one.","Disable the delete action in UI/scripts when only one page exists.","Delete widgets rather than the final page when clearing a dashboard."],"tags":["dashboard","guard","business-rule"],"backgroundTag":"cannot-delete-last-record","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}