{"record":{"id":"7c9612f1fa817cb9","repo":"tursodatabase/turso","slug":"expected-first-argument-to-be-a-function-7c9612","errorCode":null,"errorMessage":"Expected first argument to be a function","messagePattern":"Expected first argument to be a function","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"bindings/javascript/sync/packages/wasm/promise-turbopack-hack.ts","lineNumber":277,"sourceCode":"        const isReadonly = category === \"read\";\n        return new RemoteWriteStatement(\n            localStmt,\n            sql,\n            isReadonly,\n            this.#remoteWriter,\n            () => this.pull(),\n        ) as any;\n    }\n\n    /**\n     * Returns a function that executes the given function in a transaction.\n     * When remoteWrites is enabled, the entire transaction goes to remote.\n     */\n    override transaction<F extends (...args: any[]) => Promise<any>>(\n        fn: F,\n    ): TransactionFunction<F> {\n        if (typeof fn !== \"function\")\n            throw new TypeError(\"Expected first argument to be a function\");\n\n        if (!this.#remoteWriter) {\n            return super.transaction(fn);\n        }\n\n        const db = this;\n        const remoteWriter = this.#remoteWriter;\n        const wrapTxn = (mode: string) => {\n            return async (...bindParameters: any[]) => {\n                await remoteWriter.beginTransaction(mode);\n                try {\n                    const result = await fn(...bindParameters);\n                    await remoteWriter.commitTransaction();\n                    await db.pull();\n                    return result;\n                } catch (err) {\n                    await remoteWriter.rollbackTransaction();\n                    throw err;","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/tursodatabase/turso/blob/6c7252267988c76e632af00a671e4b9788dfae13/bindings/javascript/sync/packages/wasm/promise-turbopack-hack.ts#L259-L295","documentation":"transaction(fn) wraps the given callback so that the returned function executes it inside a BEGIN..COMMIT window, and it validates up front that fn is callable. Passing anything that is not a function — the result of invoking the callback early, a Promise, or undefined — fails fast with this TypeError before any transaction is started.","triggerScenarios":"db.transaction(runJob()) invokes runJob immediately and passes its return value; db.transaction(undefined) when the callback variable is misnamed, conditionally assigned, or lost in a refactor; passing a promise from an async IIFE instead of the function itself. Same behavior in the turbopack variant.","commonSituations":"Refactoring call sites around the wrapped-function API; dynamically selecting a callback that can be undefined; any-typed configuration that lets a non-function slip past TypeScript and fail at runtime.","solutions":["Pass the function reference itself: db.transaction(fn), then invoke the returned wrapper","Remove any early invocation — the () after a callback expression turns it into a value","When fn comes from dynamic input, guard with typeof fn === \"function\" before calling transaction()"],"exampleFix":"// before\nconst run = db.transaction(processOrder(order)); // calls now, passes a Promise\n\n// after\nconst run = db.transaction(() => processOrder(order)); // pass a function\nawait run();","handlingStrategy":"type-guard","validationCode":"if (typeof fn !== \"function\") {\n  throw new TypeError(\"transaction() needs the callback function itself\");\n}\nconst run = db.transaction(fn);","typeGuard":"function isCallable(fn: unknown): fn is (...args: unknown[]) => unknown {\n  return typeof fn === \"function\";\n}","tryCatchPattern":"try {\n  await db.transaction(fn)();\n} catch (err) {\n  if (err instanceof TypeError && /first argument/i.test(err.message)) {\n    // fn was not a function: fix the call site, do not retry\n    throw new Error(\"transaction() requires a function argument\");\n  }\n  throw err;\n}","preventionTips":["Pass the function reference, never its invocation result","Type the parameter explicitly (fn: () => Promise<T>) so TypeScript rejects non-functions at compile time","Avoid any-typed callback sources; validate dynamic input with typeof before calling transaction()"],"tags":["javascript","typescript","transaction","type-error","api-misuse"],"backgroundTag":"invalid-argument-value","analyzedSha":"6c7252267988c76e632af00a671e4b9788dfae13","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}