The first indexedDB.open() call made by a page appears to be flaky on first load in iOS 14.6. Its readyState stays as "pending" forever, and none of the event handlers (including "onblocked") are called. I can easily reproduce on iOS 14.6 on an iPhone 12 mini when loading a URL from scanning a QR code. 1) Clear all tabs in Safari 2) Swipe up to return to home screen 3) Open camera, scan QR code for https://tango-bravo.net/safari-indexeddb-bug/bug.html (will add a QR as an attachment) 4) Note that no onsuccess etc logs are displayed (can connect inspector at this point to verify readyState is pending) 5) Hit refresh. This time the handlers are called correctly. A workaround appears to be just to attempt to open a dummy indexedDB first that we don't care about in the main page. That one sometimes fails too (less reproducible for me) but the second one always appears to work. https://tango-bravo.net/safari-indexeddb-bug/workaround.html has a demo page of that, QR code attached here too. The closest existing bug I could find was Bug 171049, which I note saw some recent activity. However for me this doesn't depend on user state at all - reproduces even after clearing website data. This one appears to be new with iOS 14.6 (a lot of our sites broke 100% reproducibly when freshly launched from a QR code due to this underlying issue).
Created attachment 430380 [details] QR code to help reproducing the bug: https://tango-bravo.net/safari-indexeddb-bug/bug.html
Created attachment 430381 [details] QR code for the "workaround" page: https://tango-bravo.net/safari-indexeddb-bug/workaround.html
Created attachment 430382 [details] test case, html
Created attachment 430383 [details] test case, js
Created attachment 430384 [details] test case,"workaround"
Created attachment 430385 [details] Screen recording showing the bug in action
<rdar://problem/78792951>
I've also just successfully reproduced this in the latest macOS Safari 14.1.1, on macOS Big Sur 11.4. For that make sure Safari isn't running and then run `open https://tango-bravo.net/safari-indexeddb-bug/bug.html` in a terminal. Not 100% reproducible for me, but relatively frequent. Attaching a screen recording.
Created attachment 430448 [details] Screen recording showing the bug affects macOS Safari too
One more thing of interest - repeatedly looping through quitting Safari and re-opening from a terminal sometimes shows "onupgradeneeded" callback, even without clearing the website data, and without changing the version being requested. So either the hanging requests sometimes corrupt the on-disk database, leading to an "upgradeneeded" on the next attempt, or it's another symptom of the general flakiness at early startup around indexedDB.
Unable to reproduce in Safari Technology Preview 125, so perhaps this is already fixed upstream?
I'm seeing this issue as well on Safari 14.1.1 Big Sur and also seeing it fixed in the Tech Preview 125. Thank you so much for posting your workaround! I have been pulling my hair out trying to figure out what's going on.
Thank you so much for posting this workaround. That bug drove my crazy for a couple days... Couldn't figure out what was going on !
I've encountered the same problem with my web app on iOS 14.7 beta. IndexedDB is not opening when Safari is loaded for the first time. The same is true for web apps added to the home screen. A page refresh fixes this problem. The problem re-occurs when Safari is closed and then re-opened. Would be great to see an urgent fix as my web app is working offline first and depends on IndexedDB to load data.
> I've encountered the same problem with my web app on iOS 14.7 beta. > IndexedDB is not opening when Safari is loaded for the first time. The same > is true for web apps added to the home screen. A page refresh fixes this > problem. The problem re-occurs when Safari is closed and then re-opened. > > Would be great to see an urgent fix as my web app is working offline first > and depends on IndexedDB to load data. Does the workaround work for you too? It basically boils down to adding another open call for a database that you don't care about before the one that you need to work. Something like indexedDB.open("dummy", 1) appears to be enough for me, but I'd be interested if that works for PWA added to the home screen too. Of course I'd also welcome an update to fix this ASAP but as Safari is built into the iOS image, it means that updates are dependent on OS updates, so workarounds are usually required in practice for these kind of things. Apple also only tends to pull updates from the upstream webkit project every 6 months or so I believe. On a separate note, I thought I'd add that for us this was triggered by Emscripten's filesystem support that uses indexedDB - took a while to discover the hang on load was due to that run dependency never being resolved. It might not affect pages built with the current Emscripten (we're using quite an old version) but thought I'd mention it explicitly in case anyone else is searching for Emscipten WebAssembly builds hanging on first page load.
(In reply to Simon Taylor from comment #15) > On a separate note, I thought I'd add that for us this was triggered by > Emscripten's filesystem support that uses indexedDB Quick correction, the problematic Emscripten indexedDB usage was actually the implement of its Fetch API, that uses indexedDB for caching and persistent storage: https://github.com/emscripten-core/emscripten/blob/e333edadae94c34829a25c7f930937b0421fc73b/src/Fetch.js#L28 One nice feature of the workaround is we could add it to the main page, which avoided the need to modify the Emscripten runtime code.
(In reply to Simon Taylor from comment #15) > Does the workaround work for you too? Yep the workaround works for me as well in my PWA. It really confused me first because I use IndexedDB on the main thread and in a worker. The one in the worker was always working fine as it always opens after the one from the main thread. I first thought it was due to changes in my code but then found your bug report with the workaround and it made a lot more sense, so thanks for posting that otherwise I would probably still be debugging my code!!
I can also reproduce this on Safari 14.1.1 on macOS 11.4 Here's a minimal reproduction html file: <!doctype html> <html> <head> <title>indexedDB fails to open</title> </head> <body> <script> const request = indexedDB.open('testdb', 1) request.addEventListener('success', () => { alert('success') }) request.addEventListener('error', () => { alert('error') }) </script> </body> </html> Expected behavior: A "success" alert appears Actual behavior: Nothing happens This definitely should work! I confirmed that it works in current versions of Chrome and Firefox.
This IndexedDB bug broke our website https://wormhole.app for all Safari users. The most basic "hello world" usage of IndexedDB appears to not work on the first page load. If you refresh it appears to start to working. Since this bug is so easy to trigger by just opening a database, it likely affects *many* other sites as well.
I have bisected this to: http://trac.webkit.org/changeset/276556/webkit
Is there a workaround? I've got multiple sites and libraries impacted by this. The first comment mentions "the second [connection] always appears to work", is this true, or is it also a race?
"The workaround is referencing window.indexedDB before opening it."—https://twitter.com/html5test/status/1404687119570903041
Right, but I'm looking for someone from the WebKit/Safari team to confirm that. I'm worried it's just another race, and I'll go to the effort of patching libraries and sites and still be left with the problem.
Like, does: (indexedDB && indexedDB).open("foo"); …100% work around the issue?
No, just referencing indexedDB right before opening doesn't work around the issue. Setting a timer between referencing and opening also doesn't work reliably, even if the timer runs for several seconds. I haven't yet seen any failures when referencing indexedDB in the top level scope of a module (i.e. when a script is loaded) and then opening a db after network requests or user interaction. But I have no idea if it's truly reliable, and isn't a general purpose workaround.
Hi, Thanks for the bug report! The issue is that some IndexedDB messages are received in another process (network process) before it is ready to handle them. This is an issue in macOS Big Sur 11.4 and iOS 14.6 and we are working on a fix. I will make an update if the fix is available in build. To work around it, one way is to start some IndexedDB activities like deleting a database that does not exist, so another process will be notified and start preparation for IDB activities ahead. If this still not works, you may try to add some delay between dummy operation and your real database operations, like: indexedDB.deleteDatabase('dummy-database'); setTimeout(indexedDBFunction, 1000);
Will indexedDB.databases() send the same signal? My current draft workaround is: async function workaroundSafariBug() { if ( !( navigator.userAgent.includes('Safari/') && navigator.userAgent.includes('Version/') ) ) { // No point putting other browsers through this mess. return; } let intervalId; await new Promise((resolve, reject) => { const tryIdb = () => indexedDB.databases().then(resolve, reject); intervalId = setInterval(tryIdb, 100); tryIdb(); }); clearInterval(intervalId); }
I can confirm the workaround works. It's better than polling open/delete, since it doesn't have side effects. Slightly more readable version: async function workaroundSafariBug() { const isSafari = /Safari\//.test(navigator.userAgent) && !/Chrom(e|ium)\//.test(navigator.userAgent); // No point putting other browsers through this mess. if (!isSafari) return; let intervalId; await new Promise((resolve, reject) => { const tryIdb = () => indexedDB.databases().then(resolve, reject); intervalId = setInterval(tryIdb, 100); tryIdb(); }); clearInterval(intervalId); }
Thanks for posting that workaround Jake, nice idea to avoid side effects and wait until it succeeds. I haven't verified this myself, but wWorth noting on iOS this bug may well apply to all browsers as they will all be based on the same WebKit engine under the hood, so the Safari test may be a bit too restrictive.
Chrome on iOS doesn't add "Chrome/" or "Chromium/" to the user agent string, so it should be fine.
Here's a microlibrary with the fix https://www.npmjs.com/package/safari-14-idb-fix
Thanks for posting the workaround; indexedDB.databases() will work too. The issue should be fixed in macOS Monterey and iOS 15 developer beta. Please test on that. For builds before that and after iOS 14.6 (or macOS 11.4), you may use workarounds posted above.
*** This bug has been marked as a duplicate of bug 224623 ***
The provided workarounds don't work for me. I'm using indexedDB through the localforage library and the Promise is never resolved, even if the workaround methods have been passed. Moreover, if I try to access the db content through the "Storage" tab in the developer console, it is empty (it doesn't load anything with no messages/spinners visible) even if I'm 100% sure it isn't (the rare cases in which the indexedDB works, in fact, I see there are data in the db)
Are you seeing the bug on https://static-misc-3.glitch.me/safari-idb-bug-workaround/fixed.html ?
Paolo Macco: Looking at localForage, I think it creates the idb connection eagerly, so a 'wait' workaround doesn't help, since it isn't waiting. You could use https://www.npmjs.com/package/idb-keyval as an alternative (disclaimer: I'm the maintainer). It's much smaller than localForage (250 bytes vs 7kB), and it doesn't try to connect until you call the first method, so the workaround I posted here works fine.
After further investigations on Safari 14.1.1 on MacOS, I've found some more interesting details if you use the same indexedDB in multiple pages of your domain (note that I've tested all this scenarios with the latest workaround provided): 1) If you change page with the developer console open, the indexedDB is forever pending (you can verify that the db content in the storage tab is not loaded...as if it is empty). You have to close the tab to let it work again. 1b) Sometimes the issue described above happens even if you reload the same page, but this is not deterministic...it needs more investigations 2) If you WRITE on the indexedDB and then you change page, the indexedDB is forever pending. You have to change again url (if you are in localhost/index.html page, you can navigate to localhost to let the indexeddb work, even if they are the same file...). I think this issue happens with other actions like clearing the db or removing an entry, but I'm not sure. In other scenario, it seems that the workaround provided works properly. @Jake Archibald: I've tried replacing localforage with idb-keyval but I've obatined the same results, so the issues are not related to the library used.
I can't recreate those issues. Do you have a test page and some concrete steps to follow?
@Jake: I'm trying to isolate the issue in a sample project, because until now I've tried only in my live project and I think there is something else that triggers the problem.... not clear what 😅
This fix worked for me. It's essentially the same idea that Simon Taylor posted to do some dummy idb interaction before your real work. Run this before doing any other idb work: private fixSafariIndexedDB(): void { if (!window.indexedDB) return; const dummyDbName = 'safariIdbFix'; window.indexedDB.open(dummyDbName); window.indexedDB.deleteDatabase(dummyDbName); }
Does anyone feel https://bugs.webkit.org/show_bug.cgi?id=197050 is related?
I've found what the problem is. If you change page while the indexedDB has not finished writing on the store, the browser doesn't load the indexedb and the request is forever pending. You can try this example https://60d07525d461cb0007612310--distracted-ride-d4bea8.netlify.app/ If you try this on Chrome browser, for example, it works properly (after you are redirected to the landing.html page, you receive an alert). On Safari it doesn't work. You don't see that alert and you can't logout because the indexedDB hasn't been loaded. You are in the scenario I described in my previous comment (comment 37). To recreate the issue, I've put a call to the indexedDB (wrapped in a localforage call) inside the onPause listened, which is fired when you change page. I've not found (yet) any workaround to avoid the issue.
Have you tried to wrap indexedDB inside requestAnimationFrame() and see if it workarounds the issue?
With windwos.requestAnimationFrame wrapping the indexedDB operation, it seems to work... Here the example https://60d1a9b8e42616000856891f--distracted-ride-d4bea8.netlify.app/ Thank you @Binyamin. However, I noticed that the 'pause' event is not fired on Chrome when changing/reloading page, but on Safari it is.
Can we expect patch for this bug fix?
(In reply to Binyamin from comment #45) > Can we expect patch for this bug fix? Apple does not comment on future releases.
This bug is flagged as resolved being a duplicate of bug 224623, which has a patch already in the nightly version. Seems also that this blocked bug 224305, which is now set as fixed with a patch. I quickly borrowed an example from a comment above and it doesn't seem to work in the latest Safari Technology Preview (nightly) build. Maybe that's something else? https://60d07525d461cb0007612310--distracted-ride-d4bea8.netlify.app/login.html Can anyone confirm if the Nightly version is addressing this bug?
(In reply to Leo Balter from comment #47) > This bug is flagged as resolved being a duplicate of bug 224623, which has a > patch already in the nightly version. Seems also that this blocked bug > 224305, which is now set as fixed with a patch. > > I quickly borrowed an example from a comment above and it doesn't seem to > work in the latest Safari Technology Preview (nightly) build. Maybe that's > something else? > https://60d07525d461cb0007612310--distracted-ride-d4bea8.netlify.app/login. > html > > Can anyone confirm if the Nightly version is addressing this bug? As far as I know, this bug never impacted Safari Technology Preview because STP is based on trunk and this bug never impacted trunk. The bug only occurred on the product branch, in a bugfix update, due to us cherry-picking a change which worked fine on trunk but not on the branch (due to a missing dependency).
So with 224623 now being "resolved" (and this ticket being a duplicate), does that mean this fix shipped with the iOS 14.7 and/or macOS 11.5 updates last week?
(In reply to ik from comment #49) > So with 224623 now being "resolved" (and this ticket being a duplicate), > does that mean this fix shipped with the iOS 14.7 and/or macOS 11.5 updates > last week? Yes, the fix was shipped in iOS 14.7 beta 4.
I'm still seeing issues with this on IOS 14.7.1. It's not even Safari-specific. It seems like indexedDB fails to open and .onsuccess is never triggered consequently. Even if I force it to start working with it, it fails since it never opened. I've tried opening and closing a dummy database and even forcing it to wait after calling window.indexedDB; for up to 10 seconds but if it's on an iPhone it just refuses to open.
(In reply to Kasil from comment #51) > I'm still seeing issues with this on IOS 14.7.1. It's not even > Safari-specific. It seems like indexedDB fails to open and .onsuccess is > never triggered consequently. Even if I force it to start working with it, > it fails since it never opened. I've tried opening and closing a dummy > database and even forcing it to wait after calling window.indexedDB; for up > to 10 seconds but if it's on an iPhone it just refuses to open. If you're still seeing this, please file a new bug with steps to reproduce (even if only intermittently), with a link to a page demonstrating this.