tursodatabase/turso · error · Error
database must be connected before execution the function
Error message
database must be connected before execution the function
What it means
Internal guard in maybePromise.must() (common/promise.ts:994). When db.prepare() is called on a Database that has not connected yet, the returned Statement wraps a lazy chain (connect -> native prepare) and only materializes once that promise resolves. Synchronous accessors such as stmt.columns() and the stmt.reader getter call stmt.must(), which throws this error while the underlying value is still null - i.e. before the connection/prepare finished.
Solutions
- Await the statement before using sync accessors: const stmt = await db.prepare(sql); stmt.columns().
- Or connect first: await db.connect(); then prepare - statements are materialized immediately (maybeValue path).
- Keep column introspection inside async functions only; never read .columns()/.reader from sync callbacks.
- In tests, make the prepare assertion async so the lazy chain settles before must() runs.
Example fix
// before
const stmt = db.prepare("SELECT 1"); // not awaited, db not connected yet
stmt.columns(); // throws: database must be connected
// after
const stmt = await db.prepare("SELECT 1"); // connect + prepare settled
stmt.columns(); Defensive patterns
Strategy: validation
Validate before calling
const stmt = await db.prepare(sql); // resolves connect + native prepare stmt.columns(); // safe: statement materialized
Try / catch
try {
stmt.columns();
} catch (e) {
if (e instanceof Error && /must be connected/.test(e.message)) {
// lazy chain not settled: await the statement, then retry
} else throw e;
} Prevention
- Always await the Statement returned by prepare before touching sync accessors (columns/reader).
- Or await db.connect() once at startup so prepare is never lazy.
- Never read .columns()/.reader from synchronous callbacks or render paths.
When it happens
Trigger: Calling const stmt = db.prepare(sql) without awaiting, then immediately calling stmt.columns() or reading stmt.reader; using sync-style accessors on a lazily-connected (WASM/async IO) database; racing two operations where the connect promise has not settled yet; calling columns() inside a synchronous function that runs before the microtask queue flushes the connect+prepare chain.
Common situations: Porting sync API code (the compat API returns materialized statements) to the promise API where prepare returns a Promise-like Statement; framework code (e.g. a sync render path) touching stmt.columns() before an async effect completes; unit tests that forget to await the statement before introspecting columns.
Related errors
- Cannot operate on a closed connection
- Cannot operate on a closed connection
- Connection must be a SqliteConnection.
- Connection must be a TursoConnection.
- Connection must be set before executing a batch.
AI-assisted analysis of tursodatabase/turso@c1e5928725 (2026-08-20).
Data as JSON: /api/errors/4dc22fa1ac7ce091.
Report an issue: GitHub.
Appendix: source
Thrown at bindings/javascript/packages/common/promise.ts:1158
fn(result);
return result;
}
},
async resolve() {
if (promise != null) {
return await promise;
}
let valueResolve, valueReject;
promise = new Promise((resolve, reject) => {
valueResolve = x => { resolve(x); value = x; }
valueReject = reject;
});
await lazy().then(valueResolve, valueReject);
return await promise;
},
must() {
if (value == null) {
throw new Error(`database must be connected before execution the function`)
}
return value;
},
}
}
function maybeValue<T>(value: T): MaybeLazy<T> {
return {
apply(fn) { fn(value); },
resolve() { return Promise.resolve(value); },
must() { return value; },
}
}
/**
* Statement represents a prepared SQL statement that can be executed.
*/
class Statement {View on GitHub (pinned to c1e5928725)