LibraryStorage
Storage upload returns 403 even with an insert policy
Cataloged October 16, 2026 · Lovable · Bolt · Cursor · Supabase
Symptom
Upload fails with 'new row violates row-level security policy' even though the insert policy looks correct and the user is signed in.
Root cause
Supabase's storage troubleshooting page says the Storage API inserts the object and then runs RETURNING * to send metadata back. If no SELECT policy covers that new row, the database cannot return the metadata, the transaction fails, and the client sees a 403. The insert policy is not enough. The select policy has to allow the same user to read the row they just created.
Fix prompt
In this project's storage.objects policies only, pair every INSERT policy with a SELECT policy for the same role, bucket, and path prefix. Example shape, adapted to your bucket and folder layout: create policy "users insert their own files" on storage.objects for insert to authenticated with check ( bucket_id = 'docs' and (storage.foldername(name))[1] = (select auth.uid())::text ); create policy "users read their own files" on storage.objects for select to authenticated using ( bucket_id = 'docs' and (storage.foldername(name))[1] = (select auth.uid())::text ); Then retry the upload as that user. Do not open the bucket to public select to silence the error.
Paste this into the coding tool that has your own project open.
2-minute self-check
These steps are for an app you own. Do not run them against someone else's project.
- In your own dashboard, open storage.objects policies and check that each insert policy has a matching select policy.
- Upload a file in your own app as a test user. The 403 should be gone.
- As a second test user, list the first user's folder. It should be empty or denied.