"Database disk image is malformed"

C'est le code d'erreur 11, SQLITE_CORRUPT : en parcourant un b-tree, SQLite est arrivé sur une page ou un pointeur qui n'a plus de sens, et il refuse donc de faire confiance au fichier. Les lignes elles-mêmes sont presque toujours encore sur le disque — c'est la carte qui y mène qui s'est cassée — et pour les atteindre, nul besoin d'envoyer votre base de données où que ce soit.

Votre fichier ne quitte jamais votre appareil — la réparation s'exécute dans votre navigateur. 0 octet téléversé.

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.

Réparer maintenant

  1. Déposez le fichier
  2. La réparation s'exécute en local
  3. Téléchargez le résultat

Quand SQLite — ou tout ce qui repose dessus : l'historique d'un navigateur, la sauvegarde d'un téléphone, la base de données locale d'une application de messagerie, les réglages d'une application de bureau — signale "database disk image is malformed", il s'est heurté à SQLITE_CORRUPT (code de résultat 11). Il parcourait le b-tree qui indexe vos tables et a atterri sur une page dont l'octet de type, les pointeurs de cellule ou l'en-tête d'enregistrement contredisent le format ; il s'arrête donc plutôt que de renvoyer n'importe quoi. Déposez le fichier .db, .sqlite ou .sqlite3 ci-dessus et l'outil le lit page par page dans votre navigateur, suit la structure de b-tree qui subsiste, balaie le reste avec une analyse sans pointeurs et écrit chaque ligne décodable dans une base de données neuve et ouvrable — sans que le fichier quitte jamais votre machine.

Ce que "malformed" signifie au niveau de la page

Une base de données SQLite est un fichier unique découpé en pages de taille fixe — une puissance de deux comprise entre 512 et 65536 octets, stockée sous forme d'une valeur de 16 bits à l'offset 16 de l'en-tête (la valeur sur disque 1 est la façon qu'a la spécification de représenter 65536). Tout fichier commence par la chaîne magique de 16 octets SQLite format 3\0, suivie d'un en-tête de 100 octets qui consigne la taille de page, l'encodage de texte à l'offset 56 (1 = UTF-8, 2 = UTF-16le, 3 = UTF-16be), le nombre de pages déclaré à l'offset 28 et la liste des pages libres (freelist). Si la taille de page est mal lue, chaque page située après la première tombe au mauvais offset — et c'est l'une des façons dont un fichier devient "malformed" sans qu'une seule ligne soit touchée.

À l'intérieur, les données vivent dans des b-trees. Chaque page commence par un octet de type : 0x0d pour une feuille de table (qui contient les lignes réelles), 0x05 pour une page interne de table (qui ne contient que des pointeurs vers des pages filles) et 0x0a/0x02 pour les équivalents d'index. La page 1 est particulière — son en-tête de b-tree se place après l'en-tête de base de données de 100 octets — et elle est la racine de sqlite_master, la table de schéma dont les lignes sont (type, name, tbl_name, rootpage, sql). Pour lire l'une de vos tables, SQLite y cherche sa rootpage, puis descend par les pages internes jusqu'aux feuilles, en lisant dans chaque cellule la longueur de la charge utile (varint), le rowid (varint) et le corps de l'enregistrement.

Comme une requête parcourt cet arbre, un seul lien rompu empoisonne tout ce qui se trouve en dessous. Une page interne mise à zéro, un pointeur de cellule qui vise au-delà de la fin de la page, un pointeur d'extrême droite qui reboucle sur lui-même, ou un en-tête d'enregistrement dont les types série ne concordent pas — n'importe lequel de ces cas fait lever à SQLite "database disk image is malformed" dès qu'il marche sur les dégâts. Les lignes des pages feuilles saines sont intactes ; SQLite ne peut simplement pas les atteindre à travers un index rompu. PRAGMA integrity_check signale la même catégorie de défaut.

Comment un parcours brut des pages sauve vos lignes

La solution imite ce que fait la commande .recover du shell de SQLite lui-même, mais s'exécute entièrement dans le navigateur. D'abord l'outil lit sqlite_master depuis la page 1 pour connaître le nom de chaque table, ses colonnes (extraites du SQL de son CREATE TABLE) et sa rootpage, puis parcourt chaque b-tree depuis cette racine — la voie rapide et exacte quand les pointeurs sont intacts. Quand un parcours rencontre une page manquante ou invalide, il se dégrade en "incomplet" au lieu d'échouer, en conservant toutes les lignes qu'il a réunies jusqu'à la rupture.

Vient ensuite la partie qui surpasse une simple réouverture : un balayage sans pointeurs. Le scanner ignore tous les pointeurs et traite chaque page feuille de table (type 0x0d) du fichier comme un sac d'enregistrements, en décodant chaque cellule directement à partir de ses octets — la longueur de l'en-tête (varint), le tableau des types série, puis chaque valeur (le type série 0 est NULL, 8/9 sont les littéraux 0 et 1, 7 est un float64, et les codes pairs/impairs au-dessus de 12 sont des BLOB/TEXT). Les chaînes de débordement (overflow) des grandes valeurs sont suivies de page en page. C'est exactement ainsi que les lignes survivent à une page interne mise à zéro, à une page dans la freelist ou à une table supprimée : la feuille contient toujours les données même quand plus rien ne pointe vers elle. Les lignes dont le nombre de colonnes correspond sans ambiguïté à une table connue y sont réinsérées ; celles qui sont vraiment inattribuables sont écrites dans une table lost_and_found avec les colonnes pgno, cellidx, nfield, rowid et c0…cN, de sorte que rien de décodable ne soit jeté.

Enfin l'outil construit une base de données neuve avec sqlite3.wasm (chargé depuis la même origine dans /engines/sqlite/), en émettant un CREATE TABLE permissif pour chaque table — les noms de colonnes d'origine et tout INTEGER PRIMARY KEY sont conservés pour que l'alias du rowid soit préservé, mais sans contraintes NOT NULL/UNIQUE/CHECK/clé étrangère qui rejetteraient une ligne ressuscitée — puis fait un INSERT OR IGNORE de chaque ligne récupérée et exporte le résultat sous forme de .db propre. Si un fichier frère -wal (journal d'écriture anticipée) est fourni, ses trames validées sont superposées d'abord, de sorte que la récupération reflète la dernière transaction validée.

Où la donnée s'arrête vraiment — et pourquoi rien n'est téléversé

La récupération atteint ce qui est présent ; elle ne peut pas inventer ce que le disque ne conserve plus. Si le fichier a été tronqué — une copie ou une synchronisation qui s'est arrêtée trop tôt, laissant une taille qui n'est pas un multiple exact de la taille de page — toute page située après la coupure a physiquement disparu, et vous obtenez les lignes qui ont été écrites intégralement avant elle. Les cellules qui se trouvent sur des pages intactes mais dont l'en-tête d'enregistrement est incohérent avec lui-même (le classique bit-rot) sont écartées et comptabilisées, plutôt que devinées. Une base de données chiffrée (SQLCipher ou l'extension SEE) n'a pas de magie en clair — sa première page est du texte chiffré — de sorte que sans la clé il n'y a rien à parcourir, et la récupération n'est pas tentée.

Deux notes d'honnêteté sur lesquelles SQLite lui-même insiste. Les lignes supprimées peuvent réapparaître : le balayage sans pointeurs lit les pages de la freelist et les pages non compactées (vacuum), si bien que des enregistrements que vous croyiez disparus peuvent resurgir dans le résultat. Et les valeurs récupérées reflètent les classes de stockage sur disque, non les affinités de colonne déclarées — le type apparent d'une colonne peut changer. La propre consigne de SQLite est sans détour : les données extraites d'une base de données corrompue sont toujours suspectes. Vérifiez-les par rapport à une source fiable avant de vous y fier.

Tout cela s'exécute dans l'onglet de votre navigateur — le scanner est du TypeScript sans dépendances et le module d'écriture est du WASM, il n'y a donc aucun aller-retour vers un serveur. Cela compte quand la base de données est un gestionnaire de mots de passe, un historique de discussion, des données de santé ou le magasin privé d'une application : vous pouvez ouvrir l'onglet Réseau et confirmer que 0 octet du fichier ne quitte jamais votre machine.

Ce que cela peut et ne peut pas réparer

Peut réparer

  • Bases de données qui lèvent SQLITE_CORRUPT / "database disk image is malformed" à cause d'une page ou d'un pointeur de b-tree endommagé
  • Lignes sur des pages feuilles de table saines qu'une page interne rompue ou une rootpage défectueuse a rendues inaccessibles
  • Lignes sur des pages internes mises à zéro, des pages dans la freelist ou des tables supprimées, récupérées par le balayage des feuilles sans pointeurs
  • Grandes valeurs qui ont débordé sur des chaînes de pages de débordement (overflow), réassemblées pendant le parcours
  • Modifications sans checkpoint dans un fichier frère -wal, superposées avant l'analyse

Ne peut pas réparer

  • Lignes situées après la coupure dans un fichier tronqué — ces pages ont physiquement disparu
  • Cellules dont l'en-tête d'enregistrement est trop corrompu pour être décodé (bit-rot) — elles sont écartées, pas devinées
  • Bases de données chiffrées SQLCipher/SEE sans la clé (les pages sont du texte chiffré)
  • Les garanties d'origine UNIQUE/CHECK/clé étrangère — la récupération relâche les contraintes pour que les lignes ressuscitées ne soient pas rejetées
  • Un fichier de 0 octet ou sans la magie SQLite ni pages feuilles décodables

Si une réparation échoue, nous vous expliquons pourquoi (données manquantes ou structure endommagée), et vous n'êtes jamais facturé pour une réparation échouée.

Questions fréquentes

"Database disk image is malformed" signifie-t-il que mes données sont perdues ?

En général non. Cela signifie que SQLite a suivi le b-tree jusqu'à une page ou un pointeur qui viole le format et s'est arrêté — code d'erreur 11, SQLITE_CORRUPT. Les lignes des pages feuilles saines sont toujours sur le disque ; elles sont seulement inaccessibles à travers l'index rompu. Lire les pages feuilles directement et reconstruire une base de données neuve en récupère la plupart.

En quoi est-ce différent de simplement rouvrir le fichier ou d'exécuter PRAGMA integrity_check ?

Rouvrir échoue de la même façon, et integrity_check ne fait que signaler les dégâts. La récupération, elle, parcourt le b-tree là où elle le peut et, surtout, effectue une analyse sans pointeurs de chaque page feuille de table — elle sauve ainsi des lignes sur des pages vers lesquelles plus rien ne pointe, ce qu'une ouverture normale ne peut jamais atteindre.

Qu'est-ce que la table lost_and_found dans la base de données récupérée ?

C'est là que sont conservés, au lieu d'être écartés, les enregistrements qui n'ont pas pu être associés à une table connue. Chacun est stocké avec son numéro de page d'origine (pgno), son index de cellule, son nombre de champs et son rowid, ainsi que ses valeurs de colonne brutes sous forme de c0, c1, etc. — afin que vous puissiez les inspecter et les reloger à la main.

Pourquoi des lignes supprimées sont-elles apparues après la récupération ?

L'analyse sans pointeurs lit les pages de la freelist et les pages non compactées (vacuum), où SQLite laisse les anciens enregistrements jusqu'à ce que l'espace soit réutilisé. La récupération privilégie l'exhaustivité, de sorte que des lignes précédemment supprimées peuvent resurgir. Traitez toute donnée récupérée comme suspecte et vérifiez-la par rapport à une source fiable.

Ma base de données est-elle téléversée pour être récupérée ?

Non. Le fichier est lu depuis votre disque et reconstruit dans l'onglet de votre navigateur ; le scanner de pages est du TypeScript pur et le module d'écriture est sqlite3.wasm servi depuis la même origine. Vous pouvez surveiller l'onglet Réseau et confirmer que 0 octet ne sort — ce qui compte pour les historiques de discussion, les gestionnaires de mots de passe, les sauvegardes et les données de santé.

Associés : Réparer une base de données SQLite · Réparer un classeur Excel · "The file is damaged and could not be repaired" · Vérifier la promesse de zéro téléversement