Short answer
Find the comparison in the policy, function or query, and make both sides the same type with ::uuid or ::text. auth.uid() returns a uuid, while auth.jwt() ->> 'sub' and storage folder names are text, so compare uuid with auth.uid() and text with ::text. The better long-term fix is to store user IDs in a uuid column.
Rather not fix it yourself? App Fix Ticket starts with a fixed-price diagnosis, then a fixed price for the fix before any fix work.
Where the mismatch comes from, and the fix
01
A text column compared with auth.uid()
“auth.uid() returns the ID of the user making the request.” Supabase, Row Level Security
auth.uid() returns a uuid. If user_id was created as text, the policy compares uuid with text and fails. The same error can read text = uuid when the sides are swapped. Change the column to uuid, or cast in the policy. Postgres won’t alter a column that a policy, view or foreign key uses, so drop those first, run the ALTER, then recreate them. On a big table the ALTER locks and rewrites it, so run it in a quiet window.
-- best: store it as uuid alter table posts alter column user_id type uuid using user_id::uuid; -- or cast in the policy create policy "own posts" on posts for select to authenticated using ( (select auth.uid())::text = user_id );02
Storage folder names are text
“Returns an array path, with all of the subfolders that a file belongs to.” Supabase, Storage helper functions
storage.foldername() returns an array of text, so each folder name, such as (storage.foldername(name))[1], is text, and comparing it with auth.uid() fails. Compare it with a text value instead, as Supabase’s own example does.
create policy "own folder uploads" on storage.objects for insert to authenticated with check ( bucket_id = 'avatars' and (storage.foldername(name))[1] = (select auth.jwt() ->> 'sub') );03
A value from the app arrives as text
“A type cast specifies a conversion from one data type to another.” PostgreSQL, Type casts
A uuid passed into an SQL function as a text parameter, or built into a query as a string, is text inside Postgres. Declare the parameter as uuid, or cast it where you compare.
create function get_post(p_id text) returns setof posts language sql as $$ select * from posts where id = p_id::uuid; $$;04
A join between two ID columns of different types
“The cast will succeed only if a suitable type conversion operation has been defined.” PostgreSQL, Type casts
A table built by an import or an AI tool can have one ID column as text and the matching one as uuid. Change the text column to uuid so the join, its foreign key and its index all use one type. Drop any policy, view or foreign key that uses the column first, and recreate it after the ALTER.
Checked against the vendor’s docs on : Supabase docs: Row Level Security; Supabase docs: Storage access control; Supabase docs: Storage helper functions; PostgreSQL docs: Type casts.
Rather hand it over?
Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.
- from $450App Fix TicketOne reproducible bug in an existing mobile or web app, diagnosed and fixed.See scope and start
- from $450AI-Built App RescueA Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.See scope and start
“Very responsive, attentive to fixing bugs, and completed the project as needed! Thank you!”
Related: Supabase “new row violates row-level security policy” · Supabase PGRST200 (relationship) · Supabase “Could not find the function” (PGRST202) · Supabase relation does not exist (42P01)