Aller au contenu

IndexedDB : dépannage

  1. Ouvrir les outils de développement (F12), onglet Console : lire le message et le nom de l’erreur.
  2. Onglet Stockage (Firefox) ou Application (Chrome, Chromium, Edge) > IndexedDB : vérifier la base, sa version, les magasins, les index et les données.
  3. Identifier l’origine (schéma, domaine, port) : une autre origine a une autre base.
  4. Reproduire dans une fenêtre normale (la navigation privée limite IndexedDB).
console.log(await indexedDB.databases?.()); // bases de l'origine (si disponible)
console.log(await navigator.storage.estimate()); // usage et quota
Erreur (erreur.name) Cause et solution
VersionError Version demandée inférieure à celle de la base : augmenter la version, ou supprimer la base en développement
NotFoundError Magasin ou index inexistant : schéma pas à jour (version non augmentée), faute de nom
ConstraintError add d’une clé existante, ou index unique violé : put, ou traiter l’erreur
DataError Clé invalide ou absente, type de clé incompatible avec l’index, plage mal formée
DataCloneError Valeur non clonable (fonction, élément du DOM, objet de bibliothèque) : stocker des données simples
InvalidStateError Connexion fermée, transaction terminée, ou opération hors du bon contexte (createObjectStore hors upgradeneeded)
TransactionInactiveError await d’une opération étrangère à IndexedDB dans la transaction : préparer les données avant
ReadOnlyError Écriture dans une transaction readonly
QuotaExceededError Espace insuffisant : libérer, vérifier navigator.storage.estimate()
AbortError Transaction annulée (erreur précédente, abort(), mise à jour de schéma)
UnknownError Erreur interne du navigateur : base corrompue, disque plein, mode privé
SecurityError Accès interdit (données de sites bloquées, iframe sandboxée, certains contextes)

Symptôme : indexedDB.open n’appelle ni onsuccess ni onerror.

Cause Solution
Un autre onglet garde l’ancienne version ouverte (blocked) Gérer onversionchange pour fermer, informer l’utilisateur de fermer les autres onglets
Connexion non fermée dans l’application elle-même Une seule connexion par onglet, la réutiliser
upgradeneeded long (migration lourde) Découper la migration, afficher une attente
Navigateur en mode privé restrictif Prévoir un repli (stockage en mémoire)
requete.onblocked = () =>
console.warn('Fermer les autres onglets de l’application');
db.onversionchange = () => {
db.close();
location.reload();
};

Pendant le développement, supprimer la base pour réinitialiser le schéma :

indexedDB.deleteDatabase('boutique');

Ou dans les outils de développement : clic droit sur la base > supprimer, ou « Clear site data » (Application). Recharger la page ensuite. Après la suppression, la prochaine ouverture recrée la base avec la version courante du code.

Cause Vérification
Navigation privée La base est supprimée à la fermeture de la fenêtre
Éviction par le navigateur (espace insuffisant) navigator.storage.persisted() ; demander persist()
L’utilisateur efface les données du site Normal : prévoir une resynchronisation
Autre origine (http / https, www, port, sous-domaine) Vérifier l’URL exacte
Autre profil de navigateur Chaque profil a ses données
Nettoyage à la fermeture (réglage du navigateur) Paramètres de confidentialité
Symptôme Piste
Import lent Une transaction par élément : regrouper dans une transaction, mettre en file les écritures sans attendre chacune
Lecture lente getAll() de tout le magasin : index, limite, curseur
Mémoire élevée Chargement massif : curseur, pagination
Interface qui se fige Traitements lourds dans le thread principal : Web Worker (IndexedDB y est disponible)
Requêtes lentes avec Dexie Champ filtré non indexé (filter() parcourt tout) : déclarer l’index
Ouverture lente Migration lourde ou très grosse base
console.time('lecture');
const lignes = await db.getAll('clients');
console.timeEnd('lecture');

Mesurer avant d’optimiser : l’onglet Performance des outils de développement montre les blocages.

  • Les quotas et les règles d’éviction diffèrent (Firefox, Chromium, Safari).
  • La navigation privée se comporte différemment selon le navigateur (capacité réduite, ou indisponible dans de très anciennes versions).
  • Certaines méthodes récentes (indexedDB.databases(), getAll avec options, durabilité de transaction) ne sont pas partout disponibles : tester la présence avant usage.
  • Safari applique des limites plus strictes sur la conservation des données de sites peu consultés.

Tester les navigateurs ciblés ; la page de compatibilité de MDN précise la prise en charge de chaque fonction.

Dans Node.js, indexedDB n’existe pas : utiliser un faux IndexedDB :

Fenêtre de terminal
npm install -D fake-indexeddb
import 'fake-indexeddb/auto'; // définit indexedDB, IDBKeyRange… globalement
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { ouvrirBase } from '../src/lib/db.js';
test('ouvre la base', async () => {
const db = await ouvrirBase();
assert.ok(db.objectStoreNames.contains('clients'));
});

Pour des tests de bout en bout, un navigateur piloté (Playwright) est plus fidèle.

Symptôme Piste
indexedDB is not defined Exécution côté serveur : n’accéder à la base que dans le navigateur (voir Avec Astro, React et Next.js)
Hydration failed après lecture de la base Lire dans useEffect, pas pendant le rendu
Données dupliquées en développement StrictMode exécute les effets deux fois : rendre les écritures idempotentes ou nettoyer

Ubuntu 24.04 et 26.04 : différences à connaître

Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »

Aucune propre à Ubuntu. Les données de Firefox se trouvent dans le profil de l’utilisateur (avec le paquet snap, sous ~/snap/firefox/common/.mozilla/firefox/), celles de Chromium dans son propre profil : supprimer ces dossiers (navigateur fermé) réinitialise tout le stockage du navigateur, pas seulement un site.