tursodatabase/turso · error · TypeError
Expected first argument to be a function
Error message
Expected first argument to be a function
What it means
The vite promise wrapper's transaction() validates that its first argument is callable before dispatching — either to the remote-writer path (beginTransaction/commit around the callback) or to the base promise implementation. Passing anything that is not a function throws an immediate TypeError. This mirrors the standard better-sqlite3/libsql ergonomic where transaction() wraps a user callback.
Source
Thrown at bindings/javascript/sync/packages/wasm/promise-vite-dev-hack.ts:282
const isReadonly = category === "read";
return new RemoteWriteStatement(
localStmt,
sql,
isReadonly,
this.#remoteWriter,
() => this.pull(),
) as any;
}
/**
* Returns a function that executes the given function in a transaction.
* When remoteWrites is enabled, the entire transaction goes to remote.
*/
override transaction<F extends (...args: any[]) => Promise<any>>(
fn: F,
): TransactionFunction<F> {
if (typeof fn !== "function")
throw new TypeError("Expected first argument to be a function");
if (!this.#remoteWriter) {
return super.transaction(fn);
}
const db = this;
const remoteWriter = this.#remoteWriter;
const wrapTxn = (mode: string) => {
return async (...bindParameters: any[]) => {
await remoteWriter.beginTransaction(mode);
try {
const result = await fn(...bindParameters);
await remoteWriter.commitTransaction();
await db.pull();
return result;
} catch (err) {
await remoteWriter.rollbackTransaction();
throw err;View on GitHub (pinned to bad083fafb)
Solutions
- Pass the function itself, not its result: `db.transaction(fn)` not `db.transaction(fn())`
- If the callback may be missing, default it or check `typeof fn === "function"` before calling transaction()
- Let TypeScript catch it: type the parameter as `(...args: any[]) => Promise<any>` and fix the compile error at the call site
Example fix
// before const tx = db.transaction(saveRecord()); // invokes saveRecord, passes its result tx(params); // after const tx = db.transaction(saveRecord); // passes the function itself tx(params);
Defensive patterns
Strategy: type-guard
Type guard
function isAsyncFn<F>(fn: unknown): fn is (...args: any[]) => Promise<any> {
return typeof fn === 'function' && fn.constructor?.name !== 'AsyncFunction' || typeof fn === 'function';
}
// simpler and sufficient:
const isTxnFn = (f: unknown): f is (...args: any[]) => Promise<any> => typeof f === 'function';
if (!isTxnFn(fn)) throw new TypeError(`transaction() needs a function, got ${typeof fn}`);
const tx = db.transaction(fn); Try / catch
try { tx = db.transaction(fn); } catch (e) { if (e instanceof TypeError && /first argument/i.test(e.message)) { /* fix the call site — wrong argument */ } throw e; } Prevention
- Always pass the function reference, never its invocation result
- Type transaction helpers generically: `<F extends (...args: any[]) => Promise<any>>` so TS rejects non-functions
- When picking callbacks from maps, guard missing entries before calling transaction()
When it happens
Trigger: `db.transaction()` with no arguments; `db.transaction(myFn())` which calls the function and passes its return value; passing an arrow stored in a possibly-undefined variable (`db.transaction(this.handlers.save)` where the property does not exist); passing an object or string instead of a callback.
Common situations: Refactoring that renames or removes the callback but leaves the call site; dynamically selecting a callback from a map where the key is missing; copy-pasting between APIs where a SQL string is passed instead of a function; optional-chaining slips that yield undefined.
Related errors
- No active remote transaction
- Expected first argument to be a function
- transactionAsync is not supported with remoteWritesExperimen
- transactionAsync is not supported with remoteWritesExperimen
- transactionAsync() callbacks receive a Transaction handle as
AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16).
Data as JSON: /api/errors/ec07facdf97725d2.
Report an issue: GitHub.