tursodatabase/turso · error · Error

Unknown parameter name

Error message

Unknown parameter name: ${name}

What it means

bindNamed() looks up each object key via the native namedPosition(name); a return value below 0 means the SQL text contains no parameter with that name. SQLite named parameters are spelled :name, @name, or $name in SQL, and the lookup must agree with the object key, so any mismatch between the SQL placeholder names and the keys of the params object triggers this.

Solutions

  1. Make each object key exactly match the placeholder name in the SQL text (same spelling and prefix style, e.g. ':name' in SQL and the matching key form in JS)
  2. If unsure of the accepted form, test both bare and prefixed key spellings against your SQL in isolation
  3. For ?-style SQL, pass an array or positional values instead of an object
  4. Derive params from a single source (typed constant) shared by the SQL string and the bind object so renames stay in sync

Example fix

// before
const stmt = db.prepare('SELECT * FROM users WHERE id = :identifier');
await stmt.get({ id: 1 }); // throws "Unknown parameter name: id"

// after
const stmt = db.prepare('SELECT * FROM users WHERE id = :identifier');
await stmt.get({ identifier: 1 });
Defensive patterns

Strategy: validation

Validate before calling

// Keep SQL placeholders and bind keys in one typed constant so they cannot drift
const FIND_USER = {
  sql: 'SELECT * FROM users WHERE id = :id AND tenant = :tenant',
  params: (id: number, tenant: string) => ({ id, tenant }), // keys match exactly
} as const;

await db.get(FIND_USER.sql, FIND_USER.params(1, 'acme'));

Type guard

function hasOnlyStringNumberBufferValues(
  params: Record<string, unknown>
): params is Record<string, number | string | ArrayBuffer> {
  return Object.values(params).every(
    (v) => typeof v === 'number' || typeof v === 'string' || v instanceof ArrayBuffer
  );
}

Try / catch

try {
  await stmt.run({ id: 1 });
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Unknown parameter name:')) {
    const bad = e.message.split(': ')[1];
    throw new Error(`Placeholder mismatch: key "${bad}" is not in the SQL text`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing an object to stmt.run/get/all/bind whose keys don't match the SQL: `stmt.get({ id: 1 })` for 'SELECT * FROM users WHERE id = :identifier'; prefix mismatch (SQL uses :name but the key includes or omits the prefix differently than namedPosition expects); passing named params to a statement that uses ? positional placeholders.

Common situations: Renaming a SQL placeholder without updating the params object; mixing conventions between code (camelCase keys) and SQL (snake_case names); copy-pasting query text between modules with different placeholder styles; passing an object to a ?-based query where the engine treats it as named params.

Related errors


AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20). Data as JSON: /api/errors/3346a989d5ba48c8. Report an issue: GitHub.

Appendix: source

Thrown at bindings/react-native/src/Statement.ts:89

    for (let i = 0; i < params.length; i++) {
      const position = i + 1; // 1-indexed
      const value = params[i]!;

      this.bindValue(position, value);
    }
  }

  /**
   * Bind named parameters
   *
   * @param params - Object with named parameters
   */
  private bindNamed(params: Record<string, SQLiteValue>): void {
    for (const [name, value] of Object.entries(params)) {
      // Get position for named parameter
      const position = this._statement.namedPosition(name);
      if (position < 0) {
        throw new Error(`Unknown parameter name: ${name}`);
      }

      this.bindValue(position, value);
    }
  }

  /**
   * Bind a single value at a position
   *
   * @param position - 1-indexed position
   * @param value - Value to bind
   */
  private bindValue(position: number, value: SQLiteValue): void {
    if (value === null || value === undefined) {
      this._statement.bindPositionalNull(position);
    } else if (typeof value === 'number') {
      // Check if integer or float
      if (Number.isInteger(value)) {

View on GitHub (pinned to 244cde92a7)