Column 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.

Supabase and browser console
column "user_id" does not exist

Also appears as

  • column todos.user_id does not exist
  • column "user_id" of relation "todos" does not exist

Prompt to fix it

A query fails with: column "user_id" does not exist. Find every query, filter, and insert that uses this column, and compare them with the table’s real columns in the database. If a migration should have added the column, show me that migration and apply it. If the name differs only in case, fix the query or quote the name. If a text value sits in double quotes inside SQL, switch it to single quotes. Don’t rename existing columns without asking, and regenerate the database types afterward.

Paste into Layerwise or any AI coding tool.

What it means

Postgres checks every column a query mentions before it runs anything. If one isn’t in the table, the query stops with this error. Through supabase-js the name comes out with its table, like column todos.user_id does not exist, and an insert written in SQL says column "user_id" of relation "todos" does not exist.

Often the code is ahead of the database. An AI tool added user_id to a query and wrote a migration (a SQL file that changes the database) for it, but the migration never ran on the database the app uses.

Two SQL rules cause most of the rest. Postgres lowercases names that aren’t in double quotes, so select userId from todos looks for userid, and it usually adds a hint like Perhaps you meant to reference the column "todos.userId". Double quotes also mark names, never text: where status = "done" looks for a column called done. Text values take single quotes.

Common causes

  • The code expects a column that a migration was supposed to add, and the migration never ran on this database.
  • The column has a camelCase name like userId, and the query doesn’t wrap it in double quotes.
  • A text value in SQL is wrapped in double quotes, so Postgres reads it as a column name.
  • The column was renamed, and a query, view, or policy still uses the old name.
  • The app is connected to an older copy of the database, such as staging instead of production.

How to fix it

  1. Open the table in the Supabase Table Editor, or query information_schema.columns, and compare the exact column names with the query.
  2. If the column is missing, add it with a migration and run that migration on every environment the app uses.
  3. If the name is camelCase, quote it everywhere ("userId") or rename the column to snake_case, like user_id.
  4. Change text values in SQL to single quotes: where status = 'done'.
  5. Regenerate your database types with supabase gen types typescript so the editor flags wrong column names before the query runs.

Example fix

-- The table's real column names, with exact case.
select column_name, data_type
from information_schema.columns
where table_schema = 'public' and table_name = 'todos';

-- Add the column the code expects.
alter table todos add column user_id uuid references auth.users (id);

-- camelCase names need double quotes; text values need single quotes.
select "userId" from todos where status = 'done';
All errors
relation "todos" does not exist

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.

Could not find the 'avatar_url' column of 'profiles' in the schema cache

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.

null value in column "user_id" of relation "todos" violates not-null constraint

Null value in column violates not-null constraint

A save left a required column empty, and that column has no default value for Postgres to fill in.

new row violates row-level security policy for table "todos"

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.