# Database recovery

If Roscoe can't open your database at startup, the web UI will show a recovery
screen instead of the normal app. This page explains what's happening and what
your options are.

## What corruption looks like

When you open Roscoe, you see a screen titled **"Roscoe can't open your
database"** with a yellow warning icon. Below it are the path to your database
file and the error message, such as `database disk image is malformed`.

## What stays, what's lost

- **Your workflow YAML files on disk are not affected.** They live in your
  project folder, not in the database. The database only stores execution
  history.
- **Your run history is what's at risk.** That's the record of which workflows
  ran, when, and what they produced. You can re-run a workflow to get a fresh
  result, but you can't recover the original outputs of a past run.

## The recovery flow

1. The recovery screen offers one primary action: **Archive & start fresh**.
2. Clicking it opens a confirmation modal that spells out exactly what stays
   (workflow files) and what you'll lose (run history).
3. On confirm, Roscoe renames your current database file to
   `roscoe.db.corrupt-<timestamp>` and creates a new empty one. The original is
   preserved on disk. The `-wal`, `-shm`, `.bak`, and `.restore-tmp` files
   beside it are deleted, so any rows still held in an uncheckpointed
   write-ahead log are lost.
4. The recovery screen rechecks the database and the app loads normally. There
   is no page reload.

The archived file lives at `~/.roscoe/roscoe.db.corrupt-<timestamp>`. Keep it
if you want to report the problem. Delete it once you're satisfied things are
working.

## Why this happens

In rough order of likelihood:

1. **The database lives in a syncing folder** (Dropbox, iCloud Drive, OneDrive,
   Google Drive). The sync client races SQLite for the file and corrupts it
   over time. To fix this permanently, move `~/.roscoe` out of any synced
   location.
2. **Hard kill or power loss during a write.** SQLite usually recovers, but
   not always.
3. **Disk hardware issues** — bad sectors, a failing solid-state drive (SSD).
   If it keeps happening, the disk is worth checking.
4. **Editing the database in another tool** (DB Browser for SQLite, sqlite3
   CLI) and crashing the editor mid-write.

## If recovery doesn't help

If a fresh database also fails to open, something else is wrong (filesystem
permissions, full disk, the wrong Bun binary). Check the terminal output where
you started Roscoe for an error message. Then mail us at support@roscoe.run and
include:

- The error message from the terminal.
- The archived file at `~/.roscoe/roscoe.db.corrupt-<timestamp>`, if you still
  have it. We can sometimes recover the schema and rows from it.

## Details

The rest of this page is for developers reproducing the failure or reading the
source. You do not need it to recover your database.

### Reproducing corruption (for testing)

Stop the server, then:

```bash
dd if=/dev/urandom of=~/.roscoe/roscoe.db bs=1024 count=10 conv=notrunc seek=2
```

This overwrites a chunk in the middle of the database file with random bytes.
Start the server. The recovery screen should appear. Do not run this against a
database with data you care about.

You can also test in isolation by overriding `HOME`:

```bash
TEST_HOME=$(mktemp -d)
mkdir "$TEST_HOME/.roscoe"
dd if=/dev/urandom of="$TEST_HOME/.roscoe/roscoe.db" bs=1024 count=10
HOME="$TEST_HOME" bun apps/server/src/index.ts
```

Then `curl http://127.0.0.1:${ROSCOE_API_PORT:-8080}/api/health` should return
`{"status":"unavailable", ...}`.

### Reference

- Server-side: `apps/server/src/db-status.ts`, `apps/server/src/routes/admin.ts`
- DB layer: `archiveAndReset()` in `packages/db/src/client.ts`
- Web UI: `apps/web/src/components/DbRecovery/`
- Screenshot test: `apps/web/e2e/db-recovery.spec.ts` (baselines resolve through
  `snapshotPathTemplate` in `apps/web/e2e/playwright.config.ts`)

## Where to next

- [Common errors](/docs/troubleshooting/common-errors) — the error-by-error
  index, including the 503 responses a bad database produces.
- [Global vs project stores](/docs/getting-started/global-vs-project) — what
  lives in `~/.roscoe` and what lives in your project folder.
- [REST API](/docs/reference/rest-api) — the `/api/health` response shape the
  recovery screen reads.
