Skip to content

Commit

Permalink
Add idb error handling for Internal error opening backing store (#9252)
Browse files Browse the repository at this point in the history
* Add idb error handling for Internal error opening backing store

* knip

* pr feedback

* update comments
  • Loading branch information
fungairino authored and grahamlangford committed Oct 8, 2024
1 parent 221bb45 commit 3b486e8
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 8 deletions.
24 changes: 24 additions & 0 deletions src/utils/idbUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,28 @@ describe("withIdbErrorHandling", () => {

expect(deleteDB).toHaveBeenCalledWith(databaseName, expect.anything());
}, 10_000); // Increased timeout due to default backoffs in p-retry

it("should delete the database if it fails all retries with Internal error opening backing store", async () => {
const onFailedAttemptMock = jest.fn();
mockOpenIDB.mockRejectedValue(
new DOMException(
"Internal error opening backing store for indexedDB.open.",
),
);

await expect(
withIdbErrorHandling(mockOpenIDB, databaseName)(mockDbOperation, {
operationName,
shouldRetry: () => true,
onFailedAttempt: onFailedAttemptMock,
}),
).rejects.toThrow(
"Internal error opening backing store for indexedDB.open.",
);

expect(mockOpenIDB).toHaveBeenCalledTimes(4); // 1 initial + 3 retries
expect(onFailedAttemptMock).toHaveBeenCalledTimes(4);

expect(deleteDB).toHaveBeenCalledWith(databaseName, expect.anything());
}, 10_000); // Increased timeout due to default backoffs in p-retry
});
33 changes: 25 additions & 8 deletions src/utils/idbUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ export function isIDBQuotaError(error: unknown): boolean {
* Before Chrome 130, there is no way to determine if the file is missing or if some other error occurred.
* In Chrome 130 and later, the error message remains the same, the type of error is different.
* NotFoundError if the file is missing, DataError for any other error.
*
* @see https://chromestatus.com/feature/5140210640486400
* @param error the error object
*/
Expand All @@ -138,6 +139,20 @@ export function isIDBLargeValueError(error: unknown): boolean {
return message.includes("Failed to read large IndexedDB value");
}

/**
* Error occurring due to corrupt chrome profile but unclear how this happens.
* This error seems to be unrecoverable and the only solution is to delete the database.
* https://jasonsavard.com/forum/discussion/4233/unknownerror-internal-error-opening-backing-store-for-indexeddb-open
*
* @param error the error object
*/
function isIDBErrorOpeningBackingStore(error: unknown): boolean {
const message = getErrorMessage(error);
return message.includes(
"Internal error opening backing store for indexedDB.open",
);
}

/**
* The large value error could be a NotFoundError or a DataError.
* NotFoundError may be fixable on a case-by-case basis.
Expand Down Expand Up @@ -227,15 +242,17 @@ export const withIdbErrorHandling =
},
);
} catch (error) {
/**
* Any retries have failed by this point
* An error for a single value can break bulk operations on the whole DB
* We don't know of a way to drop the single bad record even if we know which one it is
* So we delete the database
*/
if (isIDBLargeValueError(error)) {
if (
// Large IndexedDB value error for a single DB entry can break bulk operations on the whole DB,
// and we don't know of a way to drop the single bad record even if we know which one it is,
// so we need to delete the whole database.
isIDBLargeValueError(error) ||
// "Internal error opening backing store for indexedDB.open" is an unrecoverable error that
// requires deleting the database.
isIDBErrorOpeningBackingStore(error)
) {
console.error(
`Deleting ${databaseName} database due to permanent IndexDB large value error.`,
`Deleting ${databaseName} database due to unrecoverable IndexDB error.`,
);
await deleteDatabase(databaseName);
}
Expand Down

0 comments on commit 3b486e8

Please sign in to comment.