Getting "database error saving new user" when signing up. This is typically caused by:
- The trigger function not being updated in Supabase
- RLS policies blocking the trigger function
- Username uniqueness constraint violations
- Trigger function errors
The trigger function uses SECURITY DEFINER which should bypass RLS, but we need to ensure the policies are correct.
-
Go to Supabase SQL Editor: https://app.supabase.com/project/gdsblffnkiswaweqokcm/sql/new
-
Check if the trigger function exists and is correct:
-- Check if trigger function exists
SELECT proname, prosrc
FROM pg_proc
WHERE proname = 'handle_new_user';- If it doesn't exist or is outdated, run this complete fix:
-- First, ensure the trigger function can bypass RLS
-- The function uses SECURITY DEFINER which should work, but let's make sure
-- Drop and recreate the function with better error handling
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS TRIGGER AS $$
DECLARE
base_username TEXT;
final_username TEXT;
username_counter INTEGER := 0;
BEGIN
-- Get base username from metadata or generate from email
base_username := COALESCE(
NEW.raw_user_meta_data->>'username',
lower(regexp_replace(split_part(NEW.email, '@', 1), '[^a-z0-9_]', '_', 'g'))
);
-- Ensure username is not empty and starts with a letter
IF base_username IS NULL OR base_username = '' THEN
base_username := 'user_' || substr(NEW.id::text, 1, 8);
ELSIF NOT (base_username ~ '^[a-z]') THEN
base_username := 'user_' || base_username;
END IF;
-- Ensure username is not too long (max 30 chars)
IF length(base_username) > 30 THEN
base_username := substr(base_username, 1, 30);
END IF;
-- Handle unique constraint: if username exists, append number
final_username := base_username;
WHILE EXISTS (SELECT 1 FROM public.profiles WHERE username = final_username) LOOP
username_counter := username_counter + 1;
final_username := base_username || '_' || username_counter;
-- Prevent infinite loop
IF username_counter > 1000 THEN
final_username := 'user_' || substr(NEW.id::text, 1, 8);
EXIT;
END IF;
END LOOP;
-- Insert profile with unique username
-- Use SECURITY DEFINER to bypass RLS
INSERT INTO public.profiles (id, username, display_name)
VALUES (
NEW.id,
final_username,
COALESCE(NEW.raw_user_meta_data->>'display_name', split_part(NEW.email, '@', 1))
)
ON CONFLICT (id) DO NOTHING; -- Prevent duplicate inserts
RETURN NEW;
EXCEPTION
WHEN unique_violation THEN
-- If username still conflicts (shouldn't happen), use UUID-based username
INSERT INTO public.profiles (id, username, display_name)
VALUES (
NEW.id,
'user_' || substr(NEW.id::text, 1, 8),
COALESCE(NEW.raw_user_meta_data->>'display_name', split_part(NEW.email, '@', 1))
)
ON CONFLICT (id) DO NOTHING;
RETURN NEW;
WHEN OTHERS THEN
-- Log error but don't fail user creation
RAISE WARNING 'Error creating profile for user %: %', NEW.id, SQLERRM;
-- Try to create with minimal data
BEGIN
INSERT INTO public.profiles (id, username, display_name)
VALUES (
NEW.id,
'user_' || substr(NEW.id::text, 1, 8),
split_part(NEW.email, '@', 1)
)
ON CONFLICT (id) DO NOTHING;
EXCEPTION
WHEN OTHERS THEN
-- If even this fails, just log and continue
RAISE WARNING 'Failed to create profile even with fallback: %', SQLERRM;
END;
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- Ensure trigger exists
DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users;
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();Make sure the RLS policies allow the trigger to work:
-- Check current policies
SELECT * FROM pg_policies WHERE tablename = 'profiles';
-- The trigger uses SECURITY DEFINER, so it should bypass RLS
-- But let's make sure the insert policy exists (even though trigger bypasses it)
-- This is just for reference - the trigger should work regardlessTest if the trigger works by checking logs:
- Go to Supabase Dashboard → Logs → Postgres Logs
- Try signing up a new user
- Check the logs for any errors from
handle_new_user
If the trigger still fails, you can manually create profiles. But first, let's check if profiles are being created:
-- Check recent profiles
SELECT id, username, display_name, created_at
FROM public.profiles
ORDER BY created_at DESC
LIMIT 10;- Username too long: Fixed by truncating to 30 chars
- Infinite loop in username generation: Fixed with counter limit
- Unique constraint violation: Fixed with better conflict handling
- RLS blocking: Should be bypassed by SECURITY DEFINER, but verify
After running the SQL above:
- Try signing up a new user
- Check if profile is created:
SELECT * FROM public.profiles WHERE id = '<user_id>'; - If profile exists, the trigger is working!