Skip to content

updateStatus reports success when RLS filtered the row out (0 rows updated, no error) #83

Description

@TortoiseWolfe

Problem

src/hooks/useEmployerApplications.ts:257-288updateStatus issues an .update() with no .select(). PostgREST returns success with zero rows affected when RLS filters the target out, so error is null and the hook proceeds to mutate local state and adjust the funnel counts regardless.

Failure scenario

  1. An admin removes an employer from employer_company_links while that employer has the console open.
  2. The employer drags an application card from "applied" to "interviewing".
  3. The RLS policy no longer matches the row → 0 rows updated, no error returned.
  4. :265-267 flips the local row to "interviewing" and :280-286 increments the funnel bar.
  5. The employer sees a successful move. Nothing was written.
  6. On refresh everything snaps back, with no explanation.

The same shape applies to any transient RLS or connectivity condition — the UI always reports success.

Fix

Add .select() and treat an empty result as a failure:

const { data, error } = await supabase
  .from('job_applications')
  .update({ status: next })
  .eq('id', id)
  .select('id');

if (error) throw error;
if (!data?.length) throw new Error('Update affected no rows — permission or row missing');

Then roll back the optimistic state and surface it to the user rather than silently diverging.

Note

Same class as #71 (a write that appears to succeed but wrote nothing) and the non-transactional writes in admin-moderation-service.ts. Worth a sweep for other .update() / .delete() calls in src/ that don't check an affected-row count — this pattern is likely not unique to this hook.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions