actualbudget/actual · error

Cannot delete the last dashboard page

Error message

Cannot delete the last dashboard page

What it means

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.

Source

Thrown at packages/loot-core/src/server/dashboard/app.ts:122

      }
    });
  },
};

async function createDashboardPage({ name }: { name: string }) {
  const id = uuidv4();
  await db.insertWithSchema('dashboard_pages', { id, name });

  return id;
}

async function deleteDashboardPage(id: string) {
  const res = await db.first<{ c: number }>(
    'SELECT count(*) as c FROM dashboard_pages WHERE tombstone = 0',
  );

  if ((res?.c ?? 0) <= 1) {
    throw new Error('Cannot delete the last dashboard page');
  }

  const deleting_widgets = await db.all<Pick<db.DbDashboard, 'id'>>(
    'SELECT id FROM dashboard WHERE dashboard_page_id = ? AND tombstone = 0',
    [id],
  );

  await batchMessages(async () => {
    await db.delete_('dashboard_pages', id);
    // Tombstone all widgets for this dashboard
    await Promise.all(
      deleting_widgets.map(({ id }) => db.delete_('dashboard', id)),
    );
  });
}

async function renameDashboardPage({ id, name }: { id: string; name: string }) {
  await db.updateWithSchema('dashboard_pages', { id, name });

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Create another dashboard page first (dashboard-page-create), then delete the unwanted page.
  2. Keep the last page and clear its widgets instead of deleting the page itself.
  3. Catch the error in UI/script code and treat 'last page' as a no-op.

Example fix

// before
await runMutator(() => deleteDashboardPage(pageId));
// after
const pages = await getDashboardPages();
if (pages.length > 1) {
  await runMutator(() => deleteDashboardPage(pageId));
}
Defensive patterns

Strategy: try-catch

Validate before calling

const pages = await send('dashboard-get-pages');
if (pages.length <= 1) {
  throw new Error('Refusing to delete the last dashboard page');
}

Try / catch

try {
  await send('dashboard-delete-page', { id });
} catch (e) {
  if (e.message === 'Cannot delete the last dashboard page') {
    console.warn('Keep at least one dashboard page; create a new page first.');
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29). Data as JSON: /api/errors/e1c4cb8bcc050a60. Report an issue: GitHub.