Skip to content

storage-sqlite: console.dir in openSqliteTransaction throws on React Native / Hermes, defeating the BEGIN retry loop #8635

Description

@gaiustemple

Which RxStorage are you using?

Premium SQLite storage (rxdb-premium/plugins/storage-sqlite) over expo-sqlite, on React Native + Hermes.

Describe the bug

openSqliteTransaction (plugins/storage-sqlite/sqlite-helpers.js) calls console.dir(err) inside its BEGIN; retry catch handler. console.dir is undefined in a production React Native / Hermes runtime, so the catch handler itself throws TypeError: undefined is not a function.

Two consequences:

  1. The real SQLite error ("Database is closed", "API misuse", a transient lock, etc.) is replaced by an opaque TypeError, so the original message/code is lost.
  2. console.dir(err) is evaluated before the retry/terminal decision, so neither branch is reached — transient errors are never retried via promiseWait(0), and terminal errors are never rethrown with their real message. Every transaction-open failure becomes a hard throw.

Offending code

Shipped (minified ESM) form:

export async function openSqliteTransaction(e, r) {
  for (var a = !1; !a;)
    try {
      ---
    } catch (e) {
      console.log("open transaction error (will retry):");
      var o = n(e);                       // errorToPlainJson
      if (console.log(o), console.dir(e), // <-- console.dir is undefined in prod Hermes -> throws here
          e.message && (e.message.includes("Database is closed") || e.message.includes("API misuse")))
        throw e;
      await t(0)                          // promiseWait — unreachable on any error path
    }
}

Root cause

React Native's console polyfill (@react-native/js-polyfills/console.js) only provides console.dir under __DEV__. In the production path (the global.nativeLoggingHook branch that always runs in a release build) the console object defines log/info/warn/error/trace/debug/table/group/groupEnd/groupCollapsed/assert/time/count but not dirdir/dirxml/clear/profile/profileEnd are only restored from the original console inside the if (__DEV__ && originalConsole) block. So console.dir === undefined in every RN/Hermes production build (iOS and Android).

Expected behavior

A failing BEGIN; is logged, then either retried (transient) or rethrown with its original error ("Database is closed" / "API misuse").

Actual behavior

The catch handler throws TypeError: undefined is not a function from console.dir, masking the real error and bypassing the retry/rethrow logic entirely.

Minimal reproduction

Run any rxdb-premium SQLite-storage app on React Native / Hermes in a release build (__DEV__ === false) and force a BEGIN; failure (e.g. close the underlying DB handle mid-write). Observed result: TypeError: undefined is not a function originating from openSqliteTransaction, rather than the underlying SQLite error, and the transaction is not retried.

Versions

  • rxdb / rxdb-premium: 17.3.0
  • React Native: 0.83.6
  • Hermes: 0.14.1

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions