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
- 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)
- If unsure of the accepted form, test both bare and prefixed key spellings against your SQL in isolation
- For ?-style SQL, pass an array or positional values instead of an object
- 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
- Derive bind keys and SQL from a single shared constant per query
- Settle on one placeholder prefix style (:name) across the codebase
- Use arrays/positional params for ?-style SQL, objects only for named placeholders
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
- Unsupported parameter type
- getAllRows failed with status
- Statement execution failed with status
- Statement has been finalized
- Statement step failed with status
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)