This error occurs when your parameterized SQL query references a placeholder like $1 or $2, but the corresponding parameter value was not provided when executing the statement. This is typically a binding mismatch between your application code and the prepared statement.
SQLSTATE 42P02 (undefined_parameter) is raised when a PostgreSQL prepared statement or EXECUTE command references a parameter placeholder (such as $1, $2, $3, etc.) that has no corresponding value supplied. PostgreSQL parameters are positional, numbered starting from $1, and each placeholder must have a matching argument when the statement is executed. If your application skips a parameter, references a parameter number that doesn't exist, or forgets to bind values entirely, PostgreSQL will reject the query with this error. This typically indicates a mismatch between how your application generates SQL and how it supplies bind variables.
Open the SQL statement that's failing and count how many $1, $2, $3, etc. placeholders appear:
-- This query has 3 parameters: $1, $2, $3
SELECT * FROM users WHERE email = $1 AND status = $2 AND created > $3;Write down the number of placeholders (in this case, 3).
Find where your application calls this query and verify the parameters array has exactly the same number of values:
// Node.js with node-postgres - CORRECT
const res = await client.query(
'SELECT * FROM users WHERE email = $1 AND status = $2 AND created > $3',
['[email protected]', 'active', '2025-01-01']
);
// WRONG - missing parameters entirely
const res = await client.query(
'SELECT * FROM users WHERE email = $1 AND status = $2 AND created > $3'
);
// WRONG - only 2 values but query has 3 placeholders
const res = await client.query(
'SELECT * FROM users WHERE email = $1 AND status = $2 AND created > $3',
['[email protected]', 'active']
);Make sure the array length matches your placeholder count.
Parameters are matched positionally, so $1 gets the first array element, $2 gets the second, etc.:
// Query references $1 (email), $2 (status), $3 (date)
const query = 'SELECT * FROM users WHERE email = $1 AND status = $2 AND created > $3';
const params = ['[email protected]', 'active', '2024-01-01'];
// $1 $2 $3
// CORRECT: array order matches placeholder order
await client.query(query, params);
// WRONG: parameters are in wrong order
await client.query(query, ['active', '[email protected]', '2024-01-01']);Reorder your parameters array to match the $1, $2, $3... sequence in the SQL.
Run your query directly in PostgreSQL to see if it works:
psql -h localhost -U postgres -d mydb -c "SELECT * FROM users WHERE email = $1"This will fail with the same error (no $1 provided). Now try with a value:
psql -h localhost -U postgres -d mydb -c "PREPARE stmt AS SELECT * FROM users WHERE email = $1; EXECUTE stmt('[email protected]');"This should work. If it does, the problem is in your application's parameter binding.
Different libraries use different placeholders:
// node-postgres uses $1, $2, $3
client.query('SELECT * FROM users WHERE id = $1', [123]);
// Some ORMs auto-convert ? to $N
// TypeORM, Sequelize, Knex may handle this differently
// Prisma uses different syntax entirely (no $N)
await prisma.users.findUnique({ where: { id: 123 } });
// Raw queries in Sequelize:
sequelize.query('SELECT * FROM users WHERE id = $1', {
bind: [123],
type: QueryTypes.SELECT
});Verify your library's exact syntax and parameter binding method, then apply the correct pattern.
Most database drivers allow query logging. Enable it to see exactly what SQL and parameters are being sent:
// node-postgres
const client = new Client({
...config,
log: (...args) => console.log('QUERY:', args)
});
// Or use environment variable for logging
process.env.NODE_DEBUG = 'pg';Run the failing query and compare the logged SQL parameters against the query string to spot mismatches.
PostgreSQL parameter placeholders ($1, $2, etc.) are only valid for values, not for identifiers (table/column names) or SQL keywords. If you need parameterized table names, use dynamic SQL construction with proper escaping via pg_quote_ident() or your driver's identifier escaping function, but keep data values in the parameters array. Some drivers or ORMs automatically convert "?" placeholders to $1, $2, so understand your tool's conventions. In prepared statements created with PREPARE, parameters must be provided in the exact same order and count every time EXECUTE is called; mixing parameter counts is a common error when reusing prepared statements across different code paths.
ERROR: syntax error at end of input
Syntax error at end of input in PostgreSQL
Bind message supplies N parameters but prepared statement requires M
Bind message supplies N parameters but prepared statement requires M in PostgreSQL
Multidimensional arrays must have sub-arrays with matching dimensions
Multidimensional arrays must have sub-arrays with matching dimensions
ERROR: value too long for type character varying
Value too long for type character varying
insufficient columns in unique constraint for partition key
How to fix "insufficient columns in unique constraint for partition key" in PostgreSQL