🧱 Суть
Ошибка:
406 Not Acceptableв Supabase часто означает не проблему с форматом данных, а то, что PostgREST не смог вернуть результат из-за ограничений доступа.
Обычно причина:
- включён RLS;
- нет подходящей политики;
- пользователь не имеет права читать нужную строку.
📦 Проблема
Например, есть запрос:
const { data, error } = await supabase
.from('user_profiles')
.select('*')
.eq('id', user.id)
.single();Таблица существует.
Строка существует.
Но Supabase возвращает:
406 Not AcceptableПочему?
Потому что RLS скрывает эту строку от текущего пользователя.
Для Supabase это выглядит так: “Я не могу показать эту запись этому пользователю”.
Почему возникает именно 406
Метод:
.single()ожидает получить ровно одну строку.
Но из-за RLS запрос фактически превращается в:
0 доступных строкТо есть:
Ожидали:
[user_profile]
Получили:
[]Из-за этого PostgREST не может вернуть ожидаемый одиночный объект.
✅ Решение
Нужно добавить политику доступа.
Например:
CREATE POLICY "Users can select their own profile"
ON public.user_profiles
FOR SELECT
USING (auth.uid() = id);Теперь:
- пользователь делает запрос;
- Supabase получает его
auth.uid(); - сравнивает с
idстроки; - если совпадает – разрешает доступ.
💻 Код
Проверка текущего пользователя:
const {
data: { user }
} = await supabase.auth.getUser();Получение профиля:
const { data, error } = await supabase
.from('user_profiles')
.select('*')
.eq('id', user.id)
.single();Политика:
CREATE POLICY "Users can read own profile"
ON user_profiles
FOR SELECT
USING (
auth.uid() = id
);Проверка при ошибке
Если получаешь 406, проверь:
- Таблица существует:
select * from user_profiles;- RLS включён:
ALTER TABLE user_profiles ENABLE ROW LEVEL SECURITY;- Есть политика
SELECT. - Пользователь авторизован.
- JWT содержит актуальную сессию.
🎯 Вывод
406в Supabase часто означает проблему с доступом, а не ошибку запроса.- Главный подозреваемый – RLS.
- Если используешь
.single(), отсутствие доступа к строке превращается в406. - Исправляется созданием правильной политики.