Skip to content
← Back to the blog
appssecurity

File uploads failing in a Lovable app? Fix Supabase Storage

Why uploads fail or images won't show in a Lovable app: storage policies, size limits, bucket names and private files. How to find the cause and fix it safely.

By Devonauts Team5 min read
Leer en español →
A man looks through a camera at his desk next to a laptop showing a grid of photos

When file uploads fail in a Lovable app, the cause is almost always one of four things: no storage policy allows the signed-in user to write to that bucket, the file is bigger than the allowed limit, the code uploads to a bucket or path that doesn't match the policy, or the upload works but the file can't be displayed because the bucket is private. The failing request in your browser's Network tab tells you which, usually in one line.

This guide shows how to read that error, how storage permissions work in Lovable Cloud and in your own Supabase project, the policy most apps need, and how to check that one user can't open another user's files.

How do I find out why the upload failed?

  1. Open the app, open the browser developer tools (Inspect), and go to the Network tab.
  2. Try the upload again. Find the request to a URL containing /storage/v1/object/.
  3. Read the status code and the response body.
What you seeLikely cause
400 or 403 with new row violates row-level security policyNo policy allows this user to upload to this bucket or path
413, or a message about the object exceeding the maximum sizeThe file is over the bucket or project size limit
An error saying the bucket wasn't foundThe bucket name in the code doesn't match the real bucket
A MIME type errorThe bucket only accepts certain file types
Upload succeeds, image shows as brokenThe bucket is private and the app uses a public URL

On Lovable Cloud, More → Cloud → Logs has a Storage logs view with the same events. On your own Supabase project, use the storage logs in the Supabase dashboard.

Why does storage refuse the upload?

Files live in a table called storage.objects, and like any table it's protected by row-level security. Supabase's storage access control docs are blunt about it: storage doesn't allow any uploads to a bucket without policies. A bucket with no policy is locked for everyone except server code using the secret key.

Different actions need different permissions:

  • Upload a new file: an INSERT policy.
  • Overwrite a file (an "upsert", common for avatars): INSERT, plus SELECT and UPDATE.
  • List or download from a private bucket: SELECT.
  • Delete: DELETE.

The classic failure is an avatar uploader that works the first time and fails on the second, because the code uses upsert: true and only an insert policy exists.

What policy do most apps need?

The common pattern is: each user can manage files inside a folder named after their own user ID. In SQL:

create policy "Users upload to their own folder"
on storage.objects for insert to authenticated
with check (
  bucket_id = 'avatars'
  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 = 'avatars'
  and (storage.foldername(name))[1] = (select auth.uid()::text)
);

Add matching update and delete policies if users can replace or remove files. For this to work, the code has to upload to a path that starts with the user's ID:

await supabase.storage.from("avatars").upload(`${user.id}/avatar.png`, file, { upsert: true });

If the code uploads to avatar.png or public/avatar.png, the policy correctly refuses it. That mismatch between path and policy is one of the most common upload bugs in AI-generated code.

On Lovable you rarely write this by hand. Describe the rule in chat ("each user can upload and replace only their own profile photo, stored in a folder with their user ID"), then review the policies Lovable created in More → Cloud → Database. For a full explanation of policies, see our guide to Supabase row level security in Lovable and Bolt.

What are the size limits?

They depend on where your storage lives:

  • Lovable Cloud: files up to 2 GB by default. You can change the Upload size limit, up to 5 GB, at the top of More → Cloud → Storage.
  • Your own Supabase project: a global limit in Storage settings, which can't exceed 50 MB on the Free plan and can go up to 500 GB on Pro and above. Each bucket can set a lower limit, never a higher one.

For large files, the upload method matters too. Supabase recommends its standard upload for small files (up to about 6 MB) and resumable uploads for bigger ones, which survive a flaky mobile connection. Videos and long PDFs from phones are where this shows up first.

Buckets can also restrict file types. A bucket that accepts image/png and image/jpeg will reject iPhone photos saved as image/heic. Either add the type or convert images before upload.

Why do uploaded images show as broken?

Because the bucket is private, which is the right default. On Lovable Cloud, new buckets are private and public buckets are blocked by a workspace setting unless an admin turns it off. A private file has no permanent public link. The code needs a signed URL that expires:

const { data } = await supabase.storage.from("documents").createSignedUrl(path, 3600);

If the app calls getPublicUrl on a private bucket, it gets an address that returns an error. Only make a bucket public if every file in it is meant for anyone on the internet, such as product photos. Our guide to public vs private buckets helps you decide.

How do I confirm it works and is safe?

  1. Upload as user A. Confirm the file appears in the bucket under A's user ID folder.
  2. Replace the file as user A, to test the upsert path.
  3. Sign in as user B and try to open A's file by its path. It must fail.
  4. Sign out and try the same. It must fail.
  5. Upload a large file from a phone on mobile data.

Step 3 is the one people skip, and it's the one that matters. If B can read A's files, you have a data leak, not an upload bug; see what to do when a user can see another user's data.

Quick answers

Why does the upload work in Lovable's preview but not for my users? You may be testing as an account the policy happens to allow, or the policy was added after your test files. Test with a fresh account.

Should I just make the bucket public to fix it? No. Public only affects reading, and it exposes every file. Fix the policy instead.

Are storage files included in a database export? No. On Lovable Cloud, download storage files separately before moving or removing the backend.

Want your storage rules checked?

Storage policies are easy to get almost right. If your app holds documents, IDs or anything private, have them reviewed: start with the free health check, see our Supabase security review and Lovable fixes, or contact us.

Still stuck with your app?

Run the free health check on your app's URL, or get the $299 App Rescue Audit: a senior engineer reviews the code and sends you a written report in 2 business days.