While working on my fork of secret, https://perchance.org/nexora-secret, I watched my own test profile vanish and tracked it to a nasty little data-loss bug that also exists upstream.
What happened
During dev I reloaded the preview. The profile bundle fetch threw a transient network error (Failed to fetch — not a 404). The console printed:
Homepage primary inbox could not be loaded. Clearing local primary inbox entry.
and the app deleted my local inbox entry: private key, upload URL, role, settings — everything. The bundle file itself was completely fine (HTTP 200 when I checked seconds later). It was just a hiccup, and the app responded by burning the keys.
Root cause
In resolveCurrentInbox, the bundle-load catch treats every error as “profile is gone” when on the homepage route with a local entry:
} catch (error) {
if (route.isHomepageRoute && currentEntry) {
// ...log...
delete state.storage.inboxes[route.inboxId];
delete state.storage.blockedUsers[route.inboxId];
if (state.storage.primaryInboxId === route.inboxId) {
state.storage.primaryInboxId = "";
}
saveStorage(state.storage);
// ...returns to an empty homepage, no error shown
No status check, no retry, no confirmation. And it’s silent — the user just sees an empty homepage.
Why it’s severe
The private key lives only in that localStorage entry (plus an optional “profile access link” if the user ever made one). The messages themselves are still on the server, but without the key they’re undecryptable forever. So a momentary network blip can permanently lock a user out of their inbox, with zero warning.
The fix (in my fork)
fetchTextFromUpload now classifies failures: all-404s → NOT_FOUND, anything else → NETWORK.
The recovery path never auto-deletes. On failure it keeps the keys and throws a clear error.
Init failures render an error card with Retry (reload) and, when a local entry exists, Remove from this device — which confirms first, same as the existing Settings → Delete.
Verified by stubbing fetch to reject: entry survives, card shows “Nothing on this device was deleted,” and explicit remove deletes exactly the intended entry.
Upstream perchance.org/secret still has the old code (same pattern around index.html:2926), so if the maintainer is reading this — happy to share the patch.
Thanks! Fixed.


