Relation does not exist
The query names a table that Postgres can’t find in this database, usually because it was never created here or has a different name.
Also appears as
- relation "public.todos" does not exist
- Could not find the table 'public.todos' in the schema cache
Prompt to fix it
My app fails with: relation "todos" does not exist (or Supabase says it could not find the table in the schema cache). Find out why the table is missing. Check which database or Supabase project the app connects to, whether a migration creates this table and was ever applied there, whether the table lives in another schema, and whether its name has capital letters that need quotes. Fix the root cause: apply the missing migration or correct the table name in the code. Don’t create a second copy of the table under a guessed name, and show me any SQL before you run it.
Paste into Layerwise or any AI coding tool.
What it means
Postgres calls tables and views “relations.” This error means the query asked for a table that doesn’t exist in the connected database under that exact name and schema (the named group a table lives in, usually public). Supabase’s API reports the same problem as code PGRST205: “Could not find the table … in the schema cache.”
AI tools often write a migration, a SQL file that changes the database, to create the table and then build pages that use it, but nothing ever runs the migration. The code is fine; the database just doesn’t have the table yet. The same error appears when the app’s environment variables point at a different project than the one you’re looking at.
Names are the other trap. Postgres lowercases any name that isn’t wrapped in double quotes. Prisma, for example, creates a table called "Todo", so select * from Todo looks for todo and fails. Names with capitals need their quotes every time.
Common causes
- The migration that creates the table was written but never run against this database.
- The app’s database URL or Supabase keys point at a different project or environment than the one you checked.
- The table lives in another schema, such as
app, and the query doesn’t name that schema. - The table was created with capital letters in quotes, like
"Todo", and the query uses the name without quotes. - A database function or trigger, such as the one that creates a profile at sign-up, refers to a table that was renamed or dropped.
How to fix it
- Compare the project URL in the app’s environment variables with the project open in your dashboard.
- In that project’s SQL editor, run
select table_schema, table_name from information_schema.tables where table_name ilike 'todos';. - If nothing comes back, run the migration or
create tablestatement the code expects. - If the table is in another schema, use the full name, like
app.todos. In supabase-js, callsupabase.schema('app').from('todos')and add the schema to the exposed schemas in the Data API settings. - If the name has capitals, quote it everywhere, like
select * from "Todo". - If Supabase’s API still can’t see a table you just created, run
notify pgrst, 'reload schema';.
Example fix
-- Is the table here, and under which schema and exact name?
select table_schema, table_name
from information_schema.tables
where table_name ilike 'todos';
-- If it's missing, create it (or run the migration that does).
create table public.todos (
id uuid primary key default gen_random_uuid(),
user_id uuid not null default auth.uid() references auth.users (id),
title text not null,
created_at timestamptz not null default now()
);
alter table public.todos enable row level security;
grant select, insert, update, delete on public.todos to authenticated;
-- Then add policies so each user reaches only their own rows.Related errors
All errorsColumn does not exist
A query names a column the table doesn’t have, often because of a migration that never ran, a camelCase name, or text in double quotes.
Could not find the column in the schema cache
An insert or update sent a field that Supabase’s API doesn’t know as a column of that table, so it refused the whole write.
Permission denied for table
The database role making the request has no grant on that table, so Postgres refuses before row-level security even runs.
New row violates row-level security policy
Postgres refused to save a row because no row-level security policy on that table lets the current user write it.
Build with an agent that checks its work
The Layerwise agent clicks through the live preview and reads the console, so it catches errors before you do.