Skip to content

Commit ec42979

Browse files
Merge pull request Expensify#814 from callstack-internal/eliran/classify-write-blobs-invalid-data
Classify "Failed to write blobs" IDB errors as INVALID_DATA (never retry)
2 parents 1eac2fe + fcfaf4e commit ec42979

2 files changed

Lines changed: 30 additions & 0 deletions

File tree

lib/storage/providers/IDBKeyValProvider/classifyError.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ function classifyIDBError(error: unknown): ValueOf<typeof StorageErrorClass> {
1414
return StorageErrorClass.INVALID_DATA;
1515
}
1616

17+
// A queued File/Blob whose backing bytes are gone — the source OS file was modified, deleted, or
18+
// renamed after being picked, so the structured clone fails at write time. Chromium reports it as
19+
// InvalidBlob (Windows) or IOError (macOS). Retrying re-reads the same dead blob and can never succeed.
20+
if (message.includes('failed to write blobs')) {
21+
return StorageErrorClass.INVALID_DATA;
22+
}
23+
1724
// Browser quota exceeded.
1825
if (name.includes('quotaexceedederror') || message.includes('quotaexceedederror')) {
1926
return StorageErrorClass.CAPACITY;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import classifyIDBError from '../../../../lib/storage/providers/IDBKeyValProvider/classifyError';
2+
import {StorageErrorClass} from '../../../../lib/storage/errors';
3+
4+
describe('classifyIDBError', () => {
5+
it.each([
6+
// Dead File/Blob in the payload — the platform-specific dialects of "Failed to write blobs".
7+
[new DOMException('Failed to write blobs (InvalidBlob)', 'DataError'), StorageErrorClass.INVALID_DATA],
8+
[new DOMException('Failed to write blobs (IOError)', 'DataError'), StorageErrorClass.INVALID_DATA],
9+
// Non-serializable payload.
10+
[new TypeError("Failed to execute 'put' on 'IDBObjectStore': something could not be cloned."), StorageErrorClass.INVALID_DATA],
11+
// Quota.
12+
[new DOMException('The quota has been exceeded.', 'QuotaExceededError'), StorageErrorClass.CAPACITY],
13+
// Backing-store corruption.
14+
[new DOMException('Internal error opening backing store for indexedDB.open.', 'UnknownError'), StorageErrorClass.FATAL],
15+
// Transient connection failures.
16+
[new DOMException('Connection to Indexed Database server lost. Refresh the page to try again', 'UnknownError'), StorageErrorClass.TRANSIENT],
17+
[new DOMException('IDB write transaction aborted without an error', 'AbortError'), StorageErrorClass.TRANSIENT],
18+
// Anything else stays UNKNOWN.
19+
[new Error('some brand new failure'), StorageErrorClass.UNKNOWN],
20+
])('classifies %s as %s', (error, expectedClass) => {
21+
expect(classifyIDBError(error)).toBe(expectedClass);
22+
});
23+
});

0 commit comments

Comments
 (0)