- SQLSTATE
- 42703
- Condition name
undefined_column- Product
- PostgreSQL
- Versions
- PostgreSQL 13 to 18 (examples run on PostgreSQL 18.6 in PGlite)
- Category
- Syntax & Names
- Last reviewed
- 24 October 2026
On this page
What it means
SQLSTATE 42703 means a column name in the statement does not match any column of the tables in scope, usually because of case, a typo, a string written in double quotes, or an alias used where it is not visible.
PostgreSQL resolves every column name against the tables in the FROM clause (and, for INSERT and UPDATE targets, against the target table). If none has it, the statement fails with 42703 (undefined_column). Names follow the same rules as table names: unquoted names are folded to lower case, so a column created as "FirstName" is only found as "FirstName", and the message shows the folded name, firstname. When a column with a similar name exists, PostgreSQL adds a HINT such as Perhaps you meant to reference the column "customers.FirstName"., which usually is the answer.
Two other causes are easy to miss. Double quotes mark identifiers, so WHERE name = "Bob" looks for a column called Bob; strings take single quotes. And an output alias from the SELECT list can be used in ORDER BY and GROUP BY but not in WHERE or HAVING: WHERE annual > 1000 fails even though salary * 12 AS annual is in the same query. SQL Server functions written with bare date parts, such as dateadd(day, 1, now()), also fail here first, because day is read as a column name.
Common causes
- The column was created with a quoted mixed-case name ("FirstName") and is referenced unquoted.
- A typo, or a name from another environment or an old version of the schema (a migration that adds the column has not run).
- A string value written in double quotes instead of single quotes, so it is read as a column name.
- An output alias used in WHERE or HAVING, where it is not visible yet.
- The column belongs to a different table than the one the alias points at, or the right table is missing from FROM.
- INSERT or UPDATE names a column that the target table does not have, or UPDATE ... SET qualifies the column with the table name.
- SQL Server or MySQL functions with bare keywords such as day or month (dateadd, datediff), which PostgreSQL reads as column names.
Diagnose it
Read-only These queries only read the system catalogs (pg_catalog, information_schema) and statistics views such as pg_stat_activity and pg_locks. They do not change data, roles or settings, so they are safe to run first.
List the real column names, with exact case
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'customers'
ORDER BY ordinal_position; Every column as stored. A name with capital letters (FirstName) must be quoted exactly in queries; all lower case names need no quotes.
Which tables have a column with this name?
Useful when the alias points at the wrong table or the column lives in a table you have not joined.
SELECT table_schema, table_name, column_name
FROM information_schema.columns
WHERE lower(column_name) = lower('firstname')
AND table_schema NOT IN ('pg_catalog', 'information_schema')
ORDER BY 1, 2; Each table that has the column, in any case. No rows means the column does not exist in this database, perhaps because a migration has not run.
How to fix it
Each fix is labelled with what it changes. Try read-only checks and the least invasive fix first, and test changes outside production.
Use the exact name, or rename the column to lower case
Changes schemaFollow the HINT and quote the mixed-case name exactly. To stop the problem for good, rename the column to lower case once and update queries that quote the old name.
SELECT "FirstName" FROM customers;
-- or rename it once
ALTER TABLE customers RENAME COLUMN "FirstName" TO first_name;
Put string values in single quotes
Read-onlySingle quotes make a string; double quotes make a name. Better still, pass values as query parameters.
SELECT * FROM customers WHERE last_name = 'Bob';
Repeat the expression, or filter in an outer query, instead of using the alias
Read-onlyWHERE cannot see SELECT aliases. Repeat the expression, or compute it in a subquery or CTE and filter outside, where the alias is a real column.
SELECT salary * 12 AS annual
FROM customers
WHERE salary * 12 > 1000;
-- or
SELECT *
FROM (SELECT id, salary * 12 AS annual FROM customers) AS t
WHERE annual > 1000;
Write date arithmetic the PostgreSQL way
Read-onlyPostgreSQL has no dateadd or datediff; add or subtract an interval, and use date_part or age for differences.
SELECT now() + interval '1 day' AS tomorrow;
Add the column if it is genuinely missing
Changes schemaIf the column should exist (code was deployed before its migration), run the migration. For UPDATE, write the target column unqualified: UPDATE customers SET salary = 5.
ALTER TABLE customers ADD COLUMN bonus numeric;
Examples
A quoted mixed-case column referenced without quotes
CREATE TABLE customers (id int, "FirstName" text, last_name text);
SELECT FirstName FROM customers;
ERROR: column "firstname" does not exist HINT: Perhaps you meant to reference the column "customers.FirstName".
Reproduced on PGlite 0.5.11 (PostgreSQL 18.6 compiled to WebAssembly), 24 October 2026.
A string value in double quotes
CREATE TABLE customers (id int, first_name text, last_name text);
SELECT * FROM customers WHERE last_name = "Bob";
ERROR: column "Bob" does not exist
Reproduced on PGlite 0.5.11 (PostgreSQL 18.6 compiled to WebAssembly), 24 October 2026.
A SELECT alias used in WHERE
CREATE TABLE customers (id int, salary numeric);
SELECT salary * 12 AS annual
FROM customers
WHERE annual > 1000;
ERROR: column "annual" does not exist
Reproduced on PGlite 0.5.11 (PostgreSQL 18.6 compiled to WebAssembly), 24 October 2026.
Inserting into a column the table does not have
CREATE TABLE customers (id int, salary numeric);
INSERT INTO customers (id, bonus) VALUES (1, 5);
ERROR: column "bonus" of relation "customers" does not exist
Reproduced on PGlite 0.5.11 (PostgreSQL 18.6 compiled to WebAssembly), 24 October 2026.
How to prevent it
Use lower case names with underscores for every column and never quote them, and turn off identifier quoting in ORMs and GUI tools that create tables. Keep application code and migrations in step, so code that reads a new column is deployed only after the migration that adds it.
Always use single quotes for strings, or better, parameters. Qualify columns with table aliases in multi-table queries, which also prevents 42702 ambiguous column errors.
Common questions
Why does PostgreSQL say column does not exist when I can see it?
Most often the column was created with capital letters inside double quotes, so it must be written the same way ("FirstName"); unquoted names are folded to lower case. Read the HINT line, which often names the column you meant.
Why is my string treated as a column name?
In PostgreSQL double quotes mark identifiers. Write string values in single quotes: WHERE status = 'active'.
Can I use a column alias in WHERE in PostgreSQL?
No. WHERE is evaluated before the SELECT list, so the alias does not exist yet; the same applies to HAVING. Repeat the expression or filter in an outer query. ORDER BY and GROUP BY can use output aliases.
Why does dateadd(day, ...) give column "day" does not exist?
dateadd is a SQL Server function. PostgreSQL first fails on the bare word day, which it reads as a column. Use interval arithmetic instead, for example now() + interval '1 day'.
Learn more on CodeWithSQL
Official documentation
- PostgreSQL error codes (Appendix A)
- Identifiers and key words (case folding and quoting)
- SELECT (output names and where they can be used)
- Date/time functions and operators
Last technically reviewed 24 October 2026; examples and diagnostics run on PostgreSQL 18.6 (PGlite 0.5.11). SQL-level examples were run in PGlite (PostgreSQL compiled to WebAssembly); examples that need a running server are shown as documented in the PostgreSQL documentation.