tursodatabase/turso · error

No connection available

Error message

No connection available

What it means

prepare() calls checkOpen() and then defensively re-checks that this._connection is set before invoking _connection.prepareSingle(sql). The connection object is created during connect() (from the native database's connect() call). This guard fires when the Database instance believes it is initialized but the native connection handle is absent — normally an internal invariant or a race with close(), since checkOpen() would otherwise throw 'Database not connected' first.

Source

Thrown at bindings/react-native/src/Database.ts:228

    const operation = this._nativeSyncDb.create();
    await driveVoidOperation(operation, this._nativeSyncDb, this._ioContext);

    // Get connection
    const connOperation = this._nativeSyncDb.connect();
    this._connection = await driveConnectionOperation(connOperation, this._nativeSyncDb, this._ioContext);
  }

  /**
   * Prepare a SQL statement
   *
   * @param sql - SQL statement to prepare
   * @returns Prepared statement
   */
  prepare(sql: string): Statement {
    this.checkOpen();

    if (!this._connection) {
      throw new Error('No connection available');
    }

    const nativeStmt = this._connection.prepareSingle(sql);
    return new Statement(nativeStmt, this._connection!, this._execLock, this._extraIo);
  }

  /**
   * Execute SQL without returning results (for DDL, multi-statement SQL)
   *
   * @param sql - SQL to execute
   */
  async exec(sql: string): Promise<void> {
    this.checkOpen();

    if (!this._connection) {
      throw new Error('No connection available');
    }

View on GitHub (pinned to 244cde92a7)

Solutions

  1. Serialize close vs. use: await all outstanding queries before calling db.close(), and gate new calls on `db.open`
  2. Check `db.open` (returns !_closed && _connection !== null) before preparing in UI code that can race unmount
  3. Give each long-lived consumer its own Database instance instead of sharing one closable instance across screens
  4. If you see it without any close() call, report it as a binding bug — _connected true with _connection null is an internal invariant violation

Example fix

// before: unmount closes the db while a render-scheduled prepare still runs
useEffect(() => {
  const stmt = db.prepare('SELECT * FROM users'); // may race close()
  return () => db.close();
}, []);

// after: guard with the `open` getter and close only after pending work
useEffect(() => {
  if (!db.open) return;
  const stmt = db.prepare('SELECT * FROM users');
  // ...
}, []);
// elsewhere: await pendingQueries; db.close();
Defensive patterns

Strategy: validation

Validate before calling

if (!db.open) {
  throw new Error('Database is not open — connect() first and close() only after all queries finish');
}
const stmt = db.prepare('SELECT * FROM users');

Type guard

function isUsableDatabase(db: Database): boolean {
  return db.open; // `open` getter: !_closed && _connection !== null
}

Try / catch

try {
  const stmt = db.prepare(sql);
} catch (e) {
  if (e instanceof Error && /closed|not connected|No connection/.test(e.message)) {
    await reopenDatabase(); // re-create + connect, then retry once
    return db.prepare(sql);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling db.prepare(sql) in a narrow window while close() is tearing the instance down (connection closed before _closed is set), or on a Database constructed but whose connect() partially failed after setting _connected. In normal flows checkOpen() catches the not-connected case first, so seeing this exact message usually means concurrent close/prepare interleaving.

Common situations: Component unmount racing a query: an effect starts `db.prepare(...)` while a cleanup handler already called db.close(); React 18 StrictMode double-mount/double-unmount; sharing one Database instance across screens and closing it from one while another still prepares statements.

Related errors


AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20). Data as JSON: /api/errors/1690752637457ea0. Report an issue: GitHub.