{"record":{"id":"35827fbce6b183b3","repo":"tursodatabase/turso","slug":"the-supplied-sql-string-contains-no-statements","errorCode":null,"errorMessage":"The supplied SQL string contains no statements","messagePattern":"The supplied SQL string contains no statements","errorType":"exception","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"bindings/javascript/packages/common/compat.ts","lineNumber":162,"sourceCode":"      name: { get: () => this.db.path },\n      readonly: { get: () => this.db.readonly },\n      open: { get: () => this.db.open },\n      memory: { get: () => this.db.memory },\n      inTransaction: { get: () => this.db.inTransaction() },\n    });\n  }\n\n  /**\n   * Prepares a SQL statement for execution.\n   *\n   * @param {string} sql - The SQL statement string to prepare.\n   */\n  prepare(sql) {\n    if (!this.open) {\n      throw new TypeError(\"The database connection is not open\");\n    }\n    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","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/bindings/javascript/packages/common/compat.ts#L144-L180","documentation":"Thrown by Database.prepare() when the SQL argument is falsy (empty string, null, undefined). This mirrors better-sqlite3's RangeError for empty statements: preparing nothing is a programming error, not a SQL error, so the compat layer rejects it before ever reaching the native engine.","triggerScenarios":"Calling db.prepare(''), db.prepare(null), or db.prepare(undefined); building SQL by string concatenation where an optional clause leaves an empty string; looping over a list of queries that contains an empty entry; passing a variable that was never assigned (typo'd identifier resolving to undefined).","commonSituations":"Dynamic query builders that join zero conditions into ''; config-driven SQL lists with blank lines not filtered; destructuring a missing property (const { sql } = row where row.sql is undefined) and passing it straight to prepare().","solutions":["Guard before preparing: if (!sql) skip or throw your own descriptive error","Filter blank statements when building dynamic SQL: parts.filter(Boolean).join(' ')","Trim and validate user/config-provided SQL before it reaches prepare()","Check for typos or missing properties when the SQL comes from destructured objects"],"exampleFix":"// before\nconst sql = conditions.length ? `WHERE ${conditions.join(' AND ')}` : '';\ndb.prepare(`SELECT * FROM t ${sql}`); // fine\n\nconst stmt = db.prepare(buildQuery()); // buildQuery() returned '' -> RangeError\n\n// after\nconst sqlText = buildQuery() ?? '';\nif (!sqlText.trim()) throw new Error('buildQuery() produced no SQL');\nconst stmt = db.prepare(sqlText);","handlingStrategy":"validation","validationCode":"function prepareSql(db: Database, sql: string | undefined | null) {\n  if (typeof sql !== 'string' || sql.trim() === '') {\n    throw new RangeError('SQL string is empty');\n  }\n  return db.prepare(sql);\n}","typeGuard":"function isNonEmptySql(sql: unknown): sql is string {\n  return typeof sql === 'string' && sql.trim().length > 0;\n}","tryCatchPattern":"try {\n  stmt = db.prepare(sql);\n} catch (err) {\n  if (err instanceof RangeError && err.message.includes('no statements')) {\n    // Programming error: log loudly with the origin of the SQL, never retry silently\n    throw new Error(`Empty SQL produced by ${sourceLocation}`);\n  }\n  throw err;\n}","preventionTips":["Filter dynamic SQL fragments with .filter(Boolean) before joining","Validate config/file-derived SQL lists for blank entries at load time","Fail fast in dev with your own descriptive error so the origin is obvious"],"tags":["turso","javascript","sql","input-validation","better-sqlite3-compat"],"backgroundTag":"empty-sql-statement","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}