tursodatabase/turso · error · RangeError

The supplied SQL string contains no statements

Error message

The supplied SQL string contains no statements

What it means

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.

Source

Thrown at bindings/javascript/packages/common/compat.ts:162

      name: { get: () => this.db.path },
      readonly: { get: () => this.db.readonly },
      open: { get: () => this.db.open },
      memory: { get: () => this.db.memory },
      inTransaction: { get: () => this.db.inTransaction() },
    });
  }

  /**
   * Prepares a SQL statement for execution.
   *
   * @param {string} sql - The SQL statement string to prepare.
   */
  prepare(sql) {
    if (!this.open) {
      throw new TypeError("The database connection is not open");
    }
    if (!sql) {
      throw new RangeError("The supplied SQL string contains no statements");
    }

    try {
      return new Statement(this.db.prepare(sql), this.db);
    } catch (err) {
      throw convertError(err);
    }
  }

  /**
   * Returns a function that executes the given function in a transaction.
   *
   * @param {function} fn - The function to wrap in a transaction.
   */
  transaction(fn) {
    if (typeof fn !== "function")
      throw new TypeError("Expected first argument to be a function");

View on GitHub (pinned to bad083fafb)

Solutions

  1. Guard before preparing: if (!sql) skip or throw your own descriptive error
  2. Filter blank statements when building dynamic SQL: parts.filter(Boolean).join(' ')
  3. Trim and validate user/config-provided SQL before it reaches prepare()
  4. Check for typos or missing properties when the SQL comes from destructured objects

Example fix

// before
const sql = conditions.length ? `WHERE ${conditions.join(' AND ')}` : '';
db.prepare(`SELECT * FROM t ${sql}`); // fine

const stmt = db.prepare(buildQuery()); // buildQuery() returned '' -> RangeError

// after
const sqlText = buildQuery() ?? '';
if (!sqlText.trim()) throw new Error('buildQuery() produced no SQL');
const stmt = db.prepare(sqlText);
Defensive patterns

Strategy: validation

Validate before calling

function prepareSql(db: Database, sql: string | undefined | null) {
  if (typeof sql !== 'string' || sql.trim() === '') {
    throw new RangeError('SQL string is empty');
  }
  return db.prepare(sql);
}

Type guard

function isNonEmptySql(sql: unknown): sql is string {
  return typeof sql === 'string' && sql.trim().length > 0;
}

Try / catch

try {
  stmt = db.prepare(sql);
} catch (err) {
  if (err instanceof RangeError && err.message.includes('no statements')) {
    // Programming error: log loudly with the origin of the SQL, never retry silently
    throw new Error(`Empty SQL produced by ${sourceLocation}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: 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).

Common situations: 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().

Related errors


AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16). Data as JSON: /api/errors/35827fbce6b183b3. Report an issue: GitHub.