MeWrite Docs

new row violates row-level security policy

SupabaseでRow Level Security (RLS) ポリシーに違反した場合のエラー

概要

SupabaseのRow Level Security (RLS) が有効なテーブルで、適切なポリシーがない、または条件を満たさない操作を実行した場合に発生するエラーです。

エラーメッセージ

new row violates row-level security policy for table "posts"
PostgrestError: permission denied for table users
Error: Row level security policy violation

原因

1. RLSポリシーが設定されていない

2. 認証されていないユーザーでのアクセス

3. ポリシー条件を満たしていない

4. 間違ったロールでアクセス

解決策

1. RLSポリシーを作成

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-- テーブルにRLSを有効化
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;

-- 認証ユーザーが自分のデータを読める
CREATE POLICY "Users can read own posts"
ON posts FOR SELECT
USING (auth.uid() = user_id);

-- 認証ユーザーが自分のデータを作成できる
CREATE POLICY "Users can insert own posts"
ON posts FOR INSERT
WITH CHECK (auth.uid() = user_id);

-- 認証ユーザーが自分のデータを更新できる
CREATE POLICY "Users can update own posts"
ON posts FOR UPDATE
USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);

-- 認証ユーザーが自分のデータを削除できる
CREATE POLICY "Users can delete own posts"
ON posts FOR DELETE
USING (auth.uid() = user_id);

2. 全ユーザーに読み取りを許可

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
-- 公開データの場合
CREATE POLICY "Anyone can read posts"
ON posts FOR SELECT
USING (true);

-- ただし、認証ユーザーのみ書き込み可能
CREATE POLICY "Authenticated users can insert"
ON posts FOR INSERT
TO authenticated
WITH CHECK (true);

3. 認証状態を確認

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import { createClient } from '@supabase/supabase-js'

const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY)

// 認証状態を確認
const { data: { user } } = await supabase.auth.getUser()

if (!user) {
  console.error('Not authenticated')
  // ログインページへリダイレクト
}

4. Service Roleキーを使用(サーバーサイドのみ)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// サーバーサイドでRLSをバイパス
import { createClient } from '@supabase/supabase-js'

const supabaseAdmin = createClient(
  SUPABASE_URL,
  SUPABASE_SERVICE_ROLE_KEY,  // 注意: クライアントサイドでは絶対に使用しない
  {
    auth: {
      autoRefreshToken: false,
      persistSession: false
    }
  }
)

// RLSをバイパスしてデータを取得
const { data } = await supabaseAdmin
  .from('posts')
  .select('*')

5. ポリシーの条件をデバッグ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
-- 現在のポリシーを確認
SELECT * FROM pg_policies WHERE tablename = 'posts';

-- 現在のユーザーIDを確認
SELECT auth.uid();

-- ポリシー条件をテスト
SELECT *
FROM posts
WHERE user_id = auth.uid();

6. 複雑なポリシーの例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
-- 管理者はすべてのデータにアクセス可能
CREATE POLICY "Admins can do anything"
ON posts
USING (
  EXISTS (
    SELECT 1 FROM users
    WHERE users.id = auth.uid()
    AND users.role = 'admin'
  )
);

-- チームメンバーは同じチームのデータにアクセス可能
CREATE POLICY "Team members can access team data"
ON posts FOR SELECT
USING (
  team_id IN (
    SELECT team_id FROM team_members
    WHERE user_id = auth.uid()
  )
);

7. RLSを一時的に無効化(開発時のみ)

1
2
3
4
5
6
7
8
-- 開発時のデバッグ用(本番では使用しない)
ALTER TABLE posts DISABLE ROW LEVEL SECURITY;

-- または、全てを許可するポリシー
CREATE POLICY "Temporary allow all"
ON posts
USING (true)
WITH CHECK (true);

8. クライアントでのエラーハンドリング

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const { data, error } = await supabase
  .from('posts')
  .insert({ title: 'New Post', user_id: user.id })

if (error) {
  if (error.code === '42501') {
    // RLSポリシー違反
    console.error('Permission denied. Check RLS policies.')
  }
  throw error
}

関連エラー

関連エラー

最終更新: 2025-12-18