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.
0LP01: invalid_grant_operation
How to fix "Invalid grant operation" (0LP01) in PostgreSQL
aggregate functions are not allowed in WHERE clause
How to fix "aggregate functions are not allowed in WHERE clause" in PostgreSQL
2200L: not_an_xml_document
How to fix "2200L: not_an_xml_document" in PostgreSQL
ERROR: ambiguous_parameter
42P08: Ambiguous parameter error
2201F: invalid_argument_for_power_function
Invalid argument for power function (2201F)