Ошибки Supabase RLS: база пустая или запись не проходит
Если в Supabase включён RLS, но нет подходящей политики, запрос на чтение не падает с ошибкой, а возвращает пустой массив; вставка же падает с «new row violates row-level security policy». Нужно написать политики для каждой операции, привязать их к auth.uid() и проверить, что запрос идёт от вошедшего пользователя.
Первая помощь и как чиним
- 1Проверить, куда идёт запрос
Убеждаемся, что приложение смотрит в тот же проект Supabase и тот же пользователь действительно вошёл.
- 2Составить карту доступа
Для каждой таблицы решаем, кто читает, создаёт, меняет и удаляет записи.
- 3Написать политики
Отдельные политики на SELECT, INSERT, UPDATE, DELETE с привязкой к auth.uid() и ролям.
- 4Проверить под разными ролями
Гость, обычный пользователь, чужой пользователь, админ — каждый видит только своё.
- 5Закрыть обходы
Проверяем представления, функции security definer и места, где используется секретный ключ.
Чинить самому или отдать в «аптечку»
Мы уже наступили на эти грабли — вам не придётся
Аптечка: что с проектом?
3 вопроса — и мы скажем, сколько стоит починка. Чек-лист безопасности проекта в подарок.
Интервью с собственником и РОПом, аудит текущей CRM и источников заявок.
1–3 дняВоронки, роли, точки контроля. Согласуем до того, как что-то настраивать.
3–5 днейНастраиваем Битрикс24 и дописываем недостающие инструменты. Демо каждую неделю.
1–4 неделиОбучение, база знаний, поддержка. Дорабатываем, пока цифры не поедут вверх.
дальше — с вамиПодробнееразвёрнутое описание, этапы и нюансы
Lovable, Bolt и другие ИИ-инструменты активно используют Supabase и часто включают RLS (Row Level Security — защиту на уровне строк). Это правильно, но политики к нему ИИ пишет неполные. Отсюда два классических симптома: приложение показывает пустой список, хотя данные в таблице есть, или при сохранении появляется new row violates row-level security policy for table.
Почему так происходит
- RLS включён, политики нет. Postgres в этом случае по умолчанию запрещает всё. Чтение не выдаёт ошибку, а просто возвращает ноль строк — отсюда «пустая база».
- Есть политика на чтение, нет на запись. Для INSERT нужна политика с
WITH CHECK, для UPDATE — иUSING, иWITH CHECK. - Пользователь не вошёл. Политика проверяет
auth.uid() = user_id, а запрос идёт без сессии, значитauth.uid()пуст. - Не заполняется
user_id. Запись создаётся без владельца, и политика чтения её потом не находит. - Обходы. Представления (view) в Postgres по умолчанию выполняются с правами владельца и могут показывать то, что RLS скрывает. Функции с
security definer— тоже.
Что проверить самому
- В Supabase → Table Editor у таблицы стоит отметка RLS enabled. Если RLS выключен — это дыра, а не решение.
- Откройте Authentication → Policies и посмотрите, есть ли политики на все нужные операции.
- В консоли браузера проверьте, что у запроса есть заголовок
Authorizationс токеном пользователя, а не только публичный ключ. - Проверьте, что в новых строках заполнено поле владельца.
- Сверьте URL проекта в коде и в панели Supabase.
Минимальный набор для таблицы «мои заказы»:
alter table orders enable row level security;
create policy "read own" on orders for select
using (auth.uid() = user_id);
create policy "insert own" on orders for insert
with check (auth.uid() = user_id);
Для представлений в Postgres 15 и новее добавьте with (security_invoker = true), чтобы к ним применялись права вызывающего.
Когда звать разработчика. Для простой схемы «каждый видит только свои записи» политики выше можно применить самостоятельно. Помощь нужна, если в проекте есть команды, компании, менеджеры и администраторы с разными правами, если данные одного пользователя должны быть видны другому по приглашению, если политики начали тормозить запросы или если вы не уверены, что тестовый вход действительно проверяет чужие данные. Ошибка в политике RLS не видна в интерфейсе, а проявляется только тогда, когда кто-то её найдёт.
Как чиним мы
Составляем матрицу доступа: таблицы, роли, операции. Пишем политики под вашу логику, включая сценарии с командами, менеджерами и админами, где простое auth.uid() = user_id не подходит. Проверяем каждую роль отдельным тестовым пользователем, включая попытки прочитать чужие данные. Ищем обходы: представления, функции, места с секретным ключом. Если логика доступа сложнее, чем удобно выражать политиками, переносим её в серверный код. Подробнее — на странице «Аптечка вайб-кода», а общие причины поломок — в статье «Почему вайб-код ломается».
Сколько стоит
Диагностика — 50 000 ₸, аудит безопасности и настройка доступа — 60 000 ₸, итого от 110 000 ₸ для небольшого проекта. Если таблиц много и есть роли, применяется коэффициент размера. Рассчитайте в калькуляторе.
Частые вопросы
Можно просто выключить RLS?
Нет. С выключенным RLS любой, у кого есть публичный ключ из вашего фронтенда, может читать и менять таблицу целиком.
Почему в SQL-редакторе Supabase данные видны, а в приложении нет?
SQL-редактор работает с правами администратора и игнорирует RLS. Приложение работает от имени пользователя или анонима, к которым применяются политики.
Ошибка появилась только на продакшене. Почему?
Чаще всего на проде пользователь не вошёл, истекла сессия или приложение указывает на другой проект Supabase с другими политиками.
Сделаем так же у вас
Короткий созвон — и вы знаете срок и цену. Или посчитайте сами за 2 минуты.