Chrome "History" database is malformed

Chrome keeps your browsing history in a plain SQLite database — a file literally named History, with no extension, in your profile folder. When one page inside it breaks, SQLite refuses the whole file and Chrome quietly starts a fresh, empty one. The rows are almost always still on disk; recovery reads them out and rebuilds a clean database.

Your file never leaves your device — repair runs in your browser. 0 bytes uploaded.

Your data is the big block — usually intact. What breaks is the small index. Repair rebuilds it.

Drop a file here or browseTap to choose a file

ZIP · Office · PDF · video · JPG · PNG · RAR/7z · SQLite — repaired right here in your browser. Nothing is uploaded

0 bytes uploadedFree: 3 repairs/day — up to 500 MB video, 100 MB docs & archives, 50 MB photos. Free download. Single repair €5.90. No account required.

Fix it now

  1. Drop the file
  2. Repair runs locally
  3. Download the result

The History file is a standard SQLite database (16-byte magic SQLite format 3\0), so when a tool reports database disk image is malformed on it, or Chrome loses your history after a crash, it is the same class of failure any SQLite file can hit: one damaged page or pointer, not wholesale data loss. Drop the History file above and the scanner opens it in your browser, walks the pages directly, rebuilds the schema, and re-inserts every row it can still decode into a fresh, openable database — the file never leaves your machine.

Chrome's History is a SQLite database with no file extension

Your history is not stored in some proprietary format — it is a SQLite database sitting in Chrome's profile directory: on Windows %LOCALAPPDATA%\Google\Chrome\User Data\Default\History, on macOS ~/Library/Application Support/Google/Chrome/Default/History, and on Linux ~/.config/google-chrome/Default/History (Chromium uses ~/.config/chromium/…, Edge …/Microsoft/Edge/…, Brave …/BraveSoftware/Brave-Browser/…). The file is called History with no extension, which is why people don't realise they can open it in any SQLite tool — rename a copy to History.db and DB Browser for SQLite will read it straight away.

Inside are the tables that make up your browsing record. urls holds one row per page you've visited — its columns are id, url, title, visit_count, typed_count, last_visit_time and hidden. visits is the timeline: each row has a url foreign key back into urls.id, a visit_time, a from_visit that points at the previous visit (so back/forward chains reconstruct), and a transition bitmask whose low byte is the core type (LINK = 0, TYPED = 1, AUTO_BOOKMARK = 2, RELOAD = 8). Alongside them sit keyword_search_terms, downloads and downloads_url_chains, segments/segment_usage (which drive the New Tab shortcuts), and a small meta table with version and last_compatible_version rows that tell Chrome which schema it's looking at.

One detail trips up everyone who exports history: the timestamps are not Unix time. last_visit_time and visit_time are stored as microseconds since 1601-01-01 00:00:00 UTC (the Chrome/WebKit epoch). To read one as a normal date you divide by 1,000,000 and subtract 11,644,473,600 seconds. Recovery preserves the raw integers exactly as they sit on disk, so the dates survive the rebuild — you just convert them afterwards.

How the History file goes malformed: pages and pointers

A SQLite database is a flat array of fixed-size pages — Chrome uses the 4096-byte default. Page 1 carries the header and the schema; every table, including urls and visits, is a b-tree whose interior pages point down to leaf pages that hold your actual rows. Chrome runs the History database in WAL (write-ahead logging) mode, so next to it you'll normally see sibling files named History-wal and History-shm; older builds and some profiles instead leave a rollback journal called History-journal.

That sidecar machinery is exactly where damage sneaks in. If the machine loses power, the disk fills, or Chrome is killed mid-checkpoint, a WAL frame can be written only halfway back into the main file — a single interior page gets an inconsistent cell pointer or a page count that disagrees with the file size. SQLite follows that pointer, finds something that isn't a valid b-tree page, and stops with Error: database disk image is malformed (11) — result code SQLITE_CORRUPT. Run PRAGMA integrity_check and you'll see the specifics: lines like *** in database main ***, Page 214: btreeInitPage() returns error code 11, row 1803 missing from index urls_url_index, or wrong # of entries in index visits_url_index.

The important part: the engine halts at the first inconsistency, but the pages it never reached are usually perfect, and your rows are still sitting untouched in their leaf pages. It's the same story as a video's missing moov index or a ZIP's broken central directory — the map broke, not the data. That's why a page-level rebuild recovers so much where opening the file normally recovers nothing.

What recovery pulls back

You don't fix a malformed History file in place — you read out everything still decodable and write it into a brand-new database, exactly the way SQLite's own .recover command works. The scanner reads every page locally, reconstructs the schema from the surviving definitions, then walks each table's b-tree and decodes the self-describing records in its leaf pages. Rows the pointer chain can no longer reach are found by a raw page sweep, and anything that decodes but matches no known table is written to a lost_and_found table rather than thrown away.

In practice that brings back the substance of your history: the urls table (addresses, page titles, visit_count, last_visit_time), the visits timeline with its transition types and from_visit chains, and — where their pages are intact — keyword_search_terms, downloads, and the segments data. If you still have the History-wal sidecar, add it in the optional slot after you drop the main file: its committed frames are overlaid before the scan, so the rebuild reflects the last committed transaction instead of the last checkpoint — often the newest few hours of browsing. The output is a fresh, openable SQLite file you download; rename it back to History, drop it into the profile folder while Chrome is closed, and your history reappears, or just query it in any SQLite viewer.

Where it genuinely stops

Recovery returns what is physically present; it cannot invent what was overwritten. Rows that were truncated off the end of the file, or whose pages were reused after a delete, are gone — no tool can bring those back. The single biggest loss with Chrome specifically is time: when Chrome opens a History file it considers malformed, it frequently deletes it and creates a fresh, empty one on the spot, so the corrupt original is overwritten in place. If that already happened, close Chrome immediately and recover from a backup or a copy of the old History/History-wal — the empty file that replaced it has nothing in it to find.

Two smaller caveats, stated plainly. Recovered values come back as their on-disk storage class, so a column's declared affinity may not be reapplied — timestamps are still the correct microsecond integers, you just convert them yourself. And recovered data from a corrupt database is always suspect: SQLite's own documentation says so, and because a raw scan also reads freelist pages, a previously-deleted URL can occasionally resurface. The recovery report says table by table what came out and what was pulled by the raw scan. None of this needs a server: the History file — which is a map of everywhere you've been — is read from your disk and rebuilt in your tab, and you can watch the Network tab to confirm 0 bytes leave.

What this can and can't fix

Can fix

  • "database disk image is malformed (11)" on the Chrome/Chromium History file from a damaged page or b-tree pointer
  • The urls table — addresses, page titles, visit_count, typed_count and last_visit_time — from surviving leaf pages
  • The visits timeline: visit_time, transition types and from_visit back/forward chains
  • keyword_search_terms, downloads and segments data where their pages are intact
  • Uncheckpointed browsing from a supplied History-wal sidecar (overlaid before the scan)
  • Corrupt header fields (bad page size or page count) with intact pages behind them

Can't fix

  • History that Chrome already deleted and replaced with a fresh empty file — the old rows were overwritten in place
  • Rows physically truncated off the end of the file, or on pages reused after a delete — those bytes no longer exist
  • A guarantee of correctness — recovered data is always suspect; deleted URLs can resurface from freelist pages, so verify it
  • Exact column affinities: values come back as their on-disk storage class (timestamps stay correct, you just re-convert them)
  • A 0-byte History file — that's a storage-device data-recovery problem first, before any SQLite rebuild

If a repair fails, we tell you why (missing data versus broken structure), and you are never charged for a failed repair.

FAQ

Where is the Chrome History file, and does it really have no extension?

Yes — it is a file literally named History, no extension, inside your profile: %LOCALAPPDATA%\Google\Chrome\User Data\Default\History on Windows, ~/Library/Application Support/Google/Chrome/Default/History on macOS, ~/.config/google-chrome/Default/History on Linux. It is an ordinary SQLite database; copy it out (close Chrome first) and drop that copy here, or rename it History.db to open it in any SQLite viewer.

What does "database disk image is malformed" mean for my history?

It's SQLite's SQLITE_CORRUPT error, result code 11: the engine followed a pointer inside the file and hit something that isn't a valid b-tree page. It does not mean every visit is gone — usually one damaged page takes the whole file down while the urls and visits rows sit intact in their leaf pages. Recovery walks the pages directly and rebuilds a clean database from what survived.

Do I need the History-wal and History-shm files?

The -wal file is worth bringing; the -shm is not. Chrome runs History in WAL mode, so your newest committed visits may live only in History-wal until they're checkpointed into the main file. Drop History first, then add History-wal in the optional sidecar slot and its committed frames are overlaid before the scan. The -shm shared-memory file holds no durable data and isn't needed.

Why did my history disappear after Chrome said the profile was corrupt?

Because Chrome's response to a History file it can't open is often to delete it and create a fresh, empty one immediately — so the corrupt original gets overwritten in place. If that happened, close Chrome right away and recover from a backup or an earlier copy of History; the new empty file has nothing to recover. The sooner you stop Chrome from writing, the more of the old database survives.

Can I put the recovered file back into Chrome?

Yes. The output is a normal SQLite database with the same urls/visits schema. Close Chrome, rename the recovered file to History, and drop it into the profile folder (remove any stale History-wal/History-shm first). Or skip Chrome entirely and query it in a SQLite viewer — just remember last_visit_time is microseconds since 1601-01-01, so divide by 1,000,000 and subtract 11,644,473,600 to get Unix time.

Related: Repair a corrupt SQLite database · Word: unreadable content · Acrobat: "the file is damaged" · Verify the zero-upload claim