Getting "Failed to upload image" error when submitting reports.
The Supabase storage bucket report-images is not configured yet.
-
Go to Supabase Dashboard:
-
Click "New bucket"
-
Configure:
- Name:
report-images - Public bucket: ✅ CHECK THIS (allows public URL access to view images)
- File size limit: 5MB (optional)
- Click "Create bucket"
- Name:
Make sure your .env.local file has the service role key:
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key-hereYou can find this in: Supabase Dashboard → Project Settings → API → service_role key (secret)
Important: The backend uses the service role key to upload files, bypassing RLS policies. No storage policies needed!
- ✅ Backend handles uploads: The
/api/uploadendpoint usesSUPABASE_SERVICE_ROLE_KEY - ✅ No RLS policies needed: Service role bypasses all Row Level Security
- ✅ Public bucket: Allows anyone to view uploaded images via public URL
- ✅ Secure: Only your backend can upload files (not exposed to client)
node scripts/test-storage.mjsThis will:
- ✅ Check if bucket exists
- ✅ Test anonymous upload
- ✅ Verify public URL access
- ✅ Clean up test file
- Start dev server:
pnpm dev - Go to: http://localhost:3000/report
- Upload an image
- Submit report
- Should succeed! ✅
# Create a test image first
curl -X POST http://localhost:3000/api/upload \
-F "file=@test-image.jpg"- ❌ Bucket doesn't exist
- ✅ Go create it in Supabase Dashboard
- ❌ Storage policies not configured
- ✅ Add the SQL policies above
- Check console logs in terminal (shows detailed error)
- Verify bucket name is exactly
report-images - Verify bucket is marked as Public
- Verify policies allow
anonrole
- ❌ Bucket not public or missing read policy
- ✅ Enable public reads in policies
Once configured, these features work:
- ✅ Anonymous report submissions with photos
- ✅ Image uploads from
/reportpage - ✅ Public image URLs for viewing reports
- ✅ Image deletion for authenticated users
User submits report with photo
↓
POST /api/upload
↓
Supabase Storage (report-images bucket)
↓
Returns public URL
↓
POST /api/reports/submit (with imageUrl)
↓
Saves to database
↓
Redirects to thank-you page
- ✅ Anonymous uploads: Allowed (for community reports)
- ✅ Public reads: Required (to view report images)
- ✅ Rate limiting: Applied at report submission level (5/day per device)
- ✅ File validation: Type & size checked before upload
⚠️ Consider: Add content moderation for production
- Go to Storage → Buckets → report-images
- Edit bucket
- Set: Max file size = 5MB
- Go to Storage → Settings
- Enable image transformations
- Automatic optimization for web delivery
CREATE POLICY "Allow authenticated delete"
ON storage.objects FOR DELETE
TO authenticated
USING (bucket_id = 'report-images');| Item | Value |
|---|---|
| Bucket name | report-images |
| Public | Yes ✅ |
| Max size | 5MB |
| Allowed types | JPEG, PNG, WebP |
| Anonymous upload | Enabled |
| Public read | Enabled |
app/api/upload/route.ts- Upload endpoint (improved error messages)app/api/reports/submit/route.ts- Report submissionscripts/test-storage.mjs- Automated test scriptscripts/setup-storage.sh- Setup instructions.github/REPORT_BACKEND_SETUP.md- Full backend documentation
Status after setup: ✅ Ready to upload images!