Skip to content

IndexedDB - Error Handling

In modern asynchronous JavaScript, the preferred way to handle errors is with Promises and async/await. The native IndexedDB API is event-based, which can be verbose. We can wrap its requests in Promises to simplify our code and use standard try...catch blocks for robust error handling.

Errors in IndexedDB can occur for various reasons:

  • Constraint violations (e.g., trying to add an object with a key that already exists).
  • Exceeding storage quotas.
  • Attempting an operation on a transaction that is no longer active.
  • Querying a non-existent object store or index.

An unhandled error will typically abort the entire transaction, rolling back any changes made within it. Proper error handling allows you to catch these issues, inform the user, and prevent the application from crashing.

Let’s start by looking at how to convert a standard event-based request into a Promise. This pattern is fundamental to working with IndexedDB in a modern way.

// A helper function to promisify an IDBRequest
function promisifyRequest(request) {
return new Promise((resolve, reject) => {
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}

Here is a complete, modern example demonstrating how to catch a ConstraintError. This error occurs when we try to add an object with a keyPath that already exists in the object store.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>IndexedDB Modern Error Handling</title>
</head>
<body>
<h1>Check the console for output.</h1>
<script>
const DB_NAME = "ErrorHandlingDB";
const DB_VERSION = 1;
const STORE_NAME = "products";
async function setupDatabase() {
const request = indexedDB.open(DB_NAME, DB_VERSION);
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains(STORE_NAME)) {
db.createObjectStore(STORE_NAME, { keyPath: "id" });
console.log(`Object store '${STORE_NAME}' created.`);
}
};
return new Promise((resolve, reject) => {
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
async function addProduct(db, product) {
const transaction = db.transaction(STORE_NAME, "readwrite");
const store = transaction.objectStore(STORE_NAME);
const request = store.add(product);
return new Promise((resolve, reject) => {
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error); // The error will be caught by our try...catch block
transaction.oncomplete = () => console.log(`Transaction completed for adding product ${product.id}.`);
});
}
async function main() {
try {
const db = await setupDatabase();
console.log("Database opened successfully.");
const product1 = { id: "p1", name: "Laptop", price: 1200 };
await addProduct(db, product1);
console.log(`Successfully added product with ID: ${product1.id}`);
// Now, let's try to add the same product again to trigger an error
console.log("Attempting to add a duplicate product...");
const product2_duplicate = { id: "p1", name: "Gaming Laptop", price: 1500 };
await addProduct(db, product2_duplicate);
} catch (error) {
console.error("An error occurred:", error.name);
if (error.name === 'ConstraintError') {
console.log("This is a ConstraintError. It likely means the product ID already exists.");
} else {
console.log("An unexpected error occurred.");
}
}
}
main();
</script>
</body>
</html>
  • ConstraintError: As shown above, this happens when a uniqueness constraint is violated (e.g., duplicate primary key).
  • TransactionInactiveError: Occurs if you try to perform an operation after a transaction has completed. Ensure all your requests are made right after creating the transaction.
  • NotFoundError: Happens if you try to access an object store or index that doesn’t exist. This often points to a versioning issue or a typo in a name.
  • DataError: Occurs when the data you are trying to save is invalid, for example, if you try to save an object that cannot be cloned.
  • Debugging Tip: Use your browser’s developer tools (Application > Storage > IndexedDB) to inspect the database, view its contents, and clear it if needed.