{"record":{"id":"af633394214b8db2","repo":"tursodatabase/turso","slug":"expected-first-argument-to-be-a-function","errorCode":null,"errorMessage":"Expected first argument to be a function","messagePattern":"Expected first argument to be a function","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"bindings/javascript/packages/common/compat.ts","lineNumber":179,"sourceCode":"    if (!sql) {\n      throw new RangeError(\"The supplied SQL string contains no statements\");\n    }\n\n    try {\n      return new Statement(this.db.prepare(sql), this.db);\n    } catch (err) {\n      throw convertError(err);\n    }\n  }\n\n  /**\n   * Returns a function that executes the given function in a transaction.\n   *\n   * @param {function} fn - The function to wrap in a transaction.\n   */\n  transaction(fn) {\n    if (typeof fn !== \"function\")\n      throw new TypeError(\"Expected first argument to be a function\");\n\n    const db = this;\n    const wrapTxn = (mode) => {\n      return (...bindParameters) => {\n        db.exec(\"BEGIN \" + mode);\n        try {\n          const result = fn(...bindParameters);\n          db.exec(\"COMMIT\");\n          return result;\n        } catch (err) {\n          db.exec(\"ROLLBACK\");\n          throw err;\n        }\n      };\n    };\n    const properties = {\n      default: { value: wrapTxn(\"\") },\n      deferred: { value: wrapTxn(\"DEFERRED\") },","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/bindings/javascript/packages/common/compat.ts#L161-L197","documentation":"Thrown by Database.transaction() when its first argument is not a function. transaction() wraps a synchronous callback between BEGIN and COMMIT/ROLLBACK, so the callback is essential; anything else (a string, an arrow-call result, undefined) is rejected up front with a TypeError.","triggerScenarios":"Calling db.transaction(fn()) instead of db.transaction(fn) (executing the function and passing its return value); passing the name of a function as a string; passing undefined because an import failed or the callback is optional and missing.","commonSituations":"Refactoring from inline callbacks to named functions and accidentally leaving parentheses in; copy-pasting better-sqlite3 examples into code where fn is conditionally defined; passing an async function - note it passes this check but breaks transaction semantics because COMMIT runs before the awaited work completes.","solutions":["Pass the function reference, not its result: db.transaction(fn), not db.transaction(fn())","Verify the callback is defined before calling transaction() (guard against undefined imports)","If you intended to pass data, restructure: transaction(fn)(data) - the wrapper takes bind parameters at call time","Keep the callback synchronous; async functions silently break rollback guarantees even though they pass the type check"],"exampleFix":"// before\nconst insertUser = db.transaction(createUser(42)); // calls fn, passes result\n\n// after\nconst insertUser = db.transaction(createUser); // reference only\ninsertUser(42);","handlingStrategy":"type-guard","validationCode":"if (typeof fn !== 'function') {\n  throw new TypeError('transaction() requires a function reference (no call parentheses)');\n}\nconst tx = db.transaction(fn);","typeGuard":"function isSyncFunction(fn: unknown): fn is (...args: unknown[]) => unknown {\n  return typeof fn === 'function' && fn.constructor?.name !== 'AsyncFunction';\n}","tryCatchPattern":null,"preventionTips":["Pass the reference, never the call result: transaction(fn), not transaction(fn())","Reject async functions too - they pass the type check but break COMMIT/ROLLBACK ordering","Lint for immediately-invoked expressions inside call arguments"],"tags":["turso","javascript","transactions","input-validation","better-sqlite3-compat"],"backgroundTag":"invalid-argument-type","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}