PostgreSQL "relation does not exist": when the table is right there
Fix PostgreSQL "ERROR: relation does not exist": check the schema and search_path, quoted names with capitals, which database you are in, and whether migrations have run.
by OhSudo ··
Checked on real software: PostgreSQL 18.6 · November 2026How we check
Part of a learning path:SQL and PostgreSQL, step by step
ERROR: relation "employee" does not existLINE 1: SELECT * FROM employee; ^“Relation” is PostgreSQL’s word for a table or a view. It’s looked for that name and not found it. That doesn’t mean the table isn’t there: it may be in another schema or another database, or have another spelling. Often it’s that last one.
Every working example on this page runs as it is in the SQL Playground.
- Your querySELECT * FROM employeelooked up in
- search_pathschemas looked in, names folded to lower caseno such name there(fails)
- Not foundrelation "employee" does not exist(breaks here)
TL;DR
SELECT current_database(), current_schema();SHOW search_path;
SELECT table_schema, table_nameFROM information_schema.tablesWHERE table_name ILIKE '%employee%';The last query shows where the table is, and its exact name.
1. A typo, or a plural
The most common one of all. Here, the table is called employees, and the query says employee:
Search for it, with a wildcard, rather than guessing:
In psql, \dt lists tables, and \dt *.* lists them in every schema.
2. Capital letters and quotes
Here’s the one that catches people. PostgreSQL lowercases names that aren’t in quotes. A tool or an ORM may create a table with quotes, keeping its capitals, and from then on it needs them each time:
Note the message: you wrote Customers, and it looked for customers. If you see that difference, this is your problem. So either quote it everywhere, or rename it, which saves trouble later on:
Quotes also explain the opposite mistake. In PostgreSQL, double quotes always mean a name, while text goes in single quotes:
3. Another schema
A schema is a folder of tables inside a database. SELECT * FROM orders only looks in the schemas listed in search_path, and normally that’s your own and public:
Here’s a table outside that path:
Name the schema, or add it to the path for this session:
To make that last one permanent for a user, run ALTER ROLE app SET search_path TO sales, public;, which applies from their next connection. A role with no rights on that schema gets permission denied for schema instead.
4. Another database
A connection only sees one database, and tables from another just don’t exist for it. It’s easy to end up in the default one, postgres, and not shop:
In psql, use \l to list databases, and \c shop to switch. Check your connection string too, as postgresql://app@localhost/postgres connects to postgres, whatever you meant.
The same goes for the wrong server: a local one when you meant Docker, or staging when you meant production. SELECT inet_server_addr(), inet_server_port(); tells you which one you’re on. A local PostgreSQL and a container both on port 5432 is a classic trap.
5. It hasn’t been created
If it isn’t anywhere, then it may not exist yet:
- Migrations didn’t run on this environment, a typical failure after a fresh deploy. Check your tool’s status command, such as
alembic current,prisma migrate statusorrails db:migrate:status. - A transaction was rolled back, taking the
CREATE TABLEwith it, since table creation is transactional in PostgreSQL. So a table you’ve just created is gone after aROLLBACK. - A temporary table only exists in the session that made it. With a connection pool, the next query can arrive on another connection, and not see it.
- A Docker volume was reset, leaving an empty database. Scripts in
/docker-entrypoint-initdb.donly run on an empty data folder.
6. It’s there, and you can’t see it
If the table exists, and you lack rights on its schema, then you may get permission denied for schema, or a role without USAGE can get this same error for it. See permission denied for table.
Shell, we have a problem!
Similar, but different: column "x" does not exist is the same idea, for a column, and also comes from double quotes used for text. permission denied for table means it exists, without your having rights. database "shop" does not exist happens when connecting. On Oracle, this error is ORA-00942, and on MySQL, ERROR 1146. To compare other databases, see the SQL Dialect Reference. To practice writing queries, try the SQL Exercises.
SELECT * FROM practice;
Practice this in the SQL Playground
Open a real PostgreSQL 18.6 database in your browser with this article’s sample data loaded.
Found this useful? Share it.
Found a mistake? Let us know at contact@ohsudo.com.