From 41bf17691903422222acc014ba88033c0fa42002 Mon Sep 17 00:00:00 2001 From: Lotus Bot Date: Thu, 21 May 2026 23:50:24 -0400 Subject: [PATCH] fix: graceful recovery for IDB schema version conflict When matrix-sdk is briefly upgraded then reverted, the local IndexedDB schema version is higher than the SDK expects. Detect the VersionError DOMException and show a clear 'Clear local data and reload' button instead of a cryptic error message. --- src/app/pages/client/ClientRoot.tsx | 31 +++++++++++++++++++++++------ src/client/initMatrix.ts | 14 ++++++++++++- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/app/pages/client/ClientRoot.tsx b/src/app/pages/client/ClientRoot.tsx index cec99db0e..e9e5741f5 100644 --- a/src/app/pages/client/ClientRoot.tsx +++ b/src/app/pages/client/ClientRoot.tsx @@ -19,6 +19,7 @@ import React, { MouseEventHandler, ReactNode, useCallback, useEffect, useState } import { clearCacheAndReload, clearLoginData, + IDB_VERSION_CONFLICT, initClient, logoutClient, startClient, @@ -201,16 +202,34 @@ export function ClientRoot({ children }: ClientRootProps) { {loadState.status === AsyncStatus.Error && ( - {`Failed to load. ${loadState.error.message}`} + <> + {loadState.error.message === IDB_VERSION_CONFLICT ? ( + <> + + Local data is from a newer app version and cannot be read. Clear local + data to continue (you will need to log in again). + + + + ) : ( + {`Failed to load. ${loadState.error.message}`} + )} + )} {startState.status === AsyncStatus.Error && ( {`Failed to start. ${startState.error.message}`} )} - + {loadState.error?.message !== IDB_VERSION_CONFLICT && ( + + )} diff --git a/src/client/initMatrix.ts b/src/client/initMatrix.ts index 498d4f75d..d4205667f 100644 --- a/src/client/initMatrix.ts +++ b/src/client/initMatrix.ts @@ -11,6 +11,10 @@ type Session = { deviceId: string; }; +// Thrown when the local IndexedDB has a higher schema version than this SDK expects. +// This happens after a downgrade (e.g. matrix-js-sdk was briefly upgraded and then reverted). +export const IDB_VERSION_CONFLICT = 'IDB_VERSION_CONFLICT'; + export const initClient = async (session: Session): Promise => { const indexedDBStore = new IndexedDBStore({ indexedDB: global.indexedDB, @@ -32,7 +36,15 @@ export const initClient = async (session: Session): Promise => { verificationMethods: ['m.sas.v1'], }); - await indexedDBStore.startup(); + try { + await indexedDBStore.startup(); + } catch (e) { + // IDB VersionError = local DB was written by a newer SDK version (schema downgrade). + if (e instanceof DOMException && e.name === 'VersionError') { + throw new Error(IDB_VERSION_CONFLICT); + } + throw e; + } await mx.initRustCrypto(); mx.setMaxListeners(50);