sequelize/sequelize · error · Error
Query includes bind parameter "$${parameterName}", but no va
Error message
Query includes bind parameter "$${parameterName}", but no value has been provided for that bind parameter. What it means
When options.bind is an array, queryRaw maps each $N token in the SQL to bind[N-1]. Line 286 throws if a parameter name is non-numeric or if its index exceeds the array length — i.e. the SQL references a positional bind the caller did not supply. This catches SQL/bind mismatches before they reach the driver.
Source
Thrown at packages/core/src/sequelize.js:287
if (!isPlainObject(options.bind) && !isBindArray) {
throw new TypeError(
'options.bind must be either a plain object (for named parameters) or an array (for numeric parameters)',
);
}
const isOracleBulkBind = this.dialect.name === 'oracle' && isBindArray && options.executeMany;
if (isOracleBulkBind) {
// skip mapBindParameters and all bind name validation
// oracle driver executeMany() expects this format
bindParameters = options.bind;
} else {
const mappedResult = mapBindParameters(sql, this.dialect);
for (const parameterName of mappedResult.parameterSet) {
if (isBindArray) {
if (!/[1-9][0-9]*/.test(parameterName) || options.bind.length < Number(parameterName)) {
throw new Error(
`Query includes bind parameter "$${parameterName}", but no value has been provided for that bind parameter.`,
);
}
} else if (!(parameterName in options.bind)) {
throw new Error(
`Query includes bind parameter "$${parameterName}", but no value has been provided for that bind parameter.`,
);
}
}
sql = mappedResult.sql;
// used by dialects that support "INOUT" parameters to map the OUT parameters back to the name the dev used.
options.bindParameterOrder = mappedResult.bindOrder;
if (mappedResult.bindOrder == null) {
bindParameters = options.bind;
} else {
bindParameters = mappedResult.bindOrder.map(key => {View on GitHub (pinned to 7e1deec499)
Solutions
- Count placeholders in the SQL and ensure the bind array has at least that many entries in the right order.
- If the SQL uses named tokens ($name), pass a plain object for bind instead of an array.
- Generate both SQL and bind list from the same source (e.g. a query builder) so they cannot drift.
Example fix
// before
await sequelize.queryRaw('SELECT $1, $2, $3', { bind: [10, 20] }); // missing $3
// after
await sequelize.queryRaw('SELECT $1, $2, $3', { bind: [10, 20, 30] }); Defensive patterns
Strategy: validation
Validate before calling
function assertArrayBindCoversSql(sql, bind) {
const tokens = [...sql.matchAll(/\$(\d+)/g)].map(m => Number(m[1]));
const max = tokens.length ? Math.max(...tokens) : 0;
if (bind.length < max) {
throw new Error(`SQL references $${max} but bind array length is ${bind.length}.`);
}
return bind;
}
await sequelize.queryRaw(sql, { bind: assertArrayBindCoversSql(sql, bind) }); Type guard
function arrayBindMatchesSql(sql, bind) {
const tokens = [...sql.matchAll(/\$(\d+)/g)].map(m => Number(m[1]));
const max = tokens.length ? Math.max(...tokens) : 0;
return Array.isArray(bind) && bind.length >= max;
} Try / catch
try {
await sequelize.queryRaw(sql, { bind });
} catch (e) {
if (/no value has been provided for that bind parameter/.test(e.message) && Array.isArray(bind)) {
throw new Error(`Bind mismatch in SQL: ${sql}. Provided ${bind.length} values.`);
} else throw e;
} Prevention
- Generate SQL and bind array together from one source to avoid drift.
- Prefer the sql`` tagged template so placeholders and values are co-located.
- Add a query lint test that asserts every $N in raw SQL has a matching bind entry.
When it happens
Trigger: SQL contains `$3` but bind array has only 2 elements; SQL contains `$x` (non-numeric token) while bind is an array (named tokens require an object).
Common situations: Editing a query and adding a new `?`/`$N` placeholder without extending the bind array; off-by-one when generating SQL dynamically; mixing named and positional syntax in the same query.
Related errors
- Sequelize#rawQuery does not accept the "replacements" option
- options.bind must be either a plain object (for named parame
- Sequelize#rawQuery requires a string as the first parameter.
AI-assisted analysis of sequelize/sequelize@7e1deec499 (2026-08-03).
Data as JSON: /data/errors/af40d1eccd4536c7.json.
Report an issue: GitHub.