jakearchibald / idb-keyval

A super-simple-small promise-based keyval store implemented with IndexedDB

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`set` rejects with `null`- possible bug in error handling

joshkel opened this issue · comments

We've occasionally seen calls to set fail with a null error. I'd like to know why set calls are failing, so I'm trying to figure out what can cause this.

From reading the specs and experimenting, I believe that null may happen under the following circumstances:

  • The transaction's abort method is called. Since idb-keyval doesn't expose its transaction object, this seems unlikely, but maybe it could happen if, e.g., the web page is reloaded in mid-write? (I don't have a deep understanding of how web APIs handle things like page reloads.)

  • A request error occurs. If I understand correctly, a request's error event bubbles to the transaction (because the request's parent is the transaction). After the error event is done, it aborts the transaction, which sets IDBTransaction.error and fires the transaction's abort event.

    set causes its promise to be rejected on either an error event (which may bubble from the request) or an abort event (see here and here). Since the error event fires first and does not set IDBTransaction.error, a request error causes the promise to be rejected without the error being available.

Are you aware of other circumstances that may cause a null rejection?

Can you update idb-keyval to expose the error if the request fails?

See https://codesandbox.io/s/serene-danilo-lseiit?file=/src/index.js for a demonstration. It looks like a transaction's error event could get the error details via event.target.error (although that doesn't fit as well with idb-keyval's as-small-as-possible goal).

Am I right that you don't have a reproducible case for this, but you're seeing it in logging?

@jakearchibald Correct; I have not been able to reproduce it locally.

No problem, thanks for all the details. I'll see if I can figure something out.

I have what appears to be a reproducible test case:

https://codesandbox.io/s/goofy-kowalevski-zncg4g?file=/src/index.js

I've observed this in Safari for Mac and Safari for iPhone. Each time you click "set value", it writes a bunch of values to IndexedDB. After doing this ~19 times, Safari should prompt you to allow more storage. If you choose to not allow, then the error handler is called with null.

(I tried other failure modes, such as saving a non-structured-cloneable object or exceeding the quota in Chrome. The error handler received the error in these cases, as intended. That did not match my understanding of the spec, so I may have misunderstood things.)

See #164 for a potential fix.

Some additional notes from my testing:

  • https://codesandbox.io/s/goofy-kowalevski-zncg4g is a sandbox for experimenting with quota errors; however, the Safari behavior I described above seems to be easier to reproduce by navigating directly to https://zncg4g.csb.app/, instead of loading within CodeSandbox.
  • My comment above about the error behavior when saving a non-structured-cloneable object is irrelevant; that immediately (synchronously) throws an error, rather than firing error + abort events, so it's not relevant to this discussion.