Skip to content

Fix register-by-wallet vs onboard upsert race condition #633

@realproject7

Description

@realproject7

Problem

register-by-wallet and onboard are two separate API routes that both upsert the same users row. When called concurrently (e.g., wallet connect triggers register while user clicks refresh), they race:

  1. Both query for existing user separately
  2. Both attempt INSERT — first succeeds, second gets 23505 (unique violation)
  3. Second falls back to UPDATE but uses different conflict keys (FID vs primary_address)
  4. Result: partial updates, corrupted row with mixed data from both routes

Root Cause

Both routes use INSERT-then-catch-23505-then-UPDATE pattern with different conflict resolution:

  • register-by-wallet: updates by fid or primary_address
  • onboard: updates by existingUser.id

Fix

  1. Unify the upsert logic — both routes should use the same conflict resolution strategy, preferably .upsert() with explicit conflict keys
  2. Use existingUser.id as the primary update key in both routes (most reliable — UUID, always unique)
  3. Add a shared upsertUser() helper in lib/actions.ts that both routes call, ensuring consistent behavior
  4. Handle all user types correctly: FID users, wallet-only users, agent users

Files to modify

  • src/app/api/user/register-by-wallet/route.ts — use shared upsert logic
  • src/app/api/user/onboard/route.ts — use shared upsert logic
  • lib/actions.ts or new lib/user-upsert.ts — shared upsert helper

Branch

task/633-upsert-race-fix

Acceptance criteria

  • Concurrent register + onboard calls don't corrupt user row
  • Both routes use identical conflict resolution
  • FID users, wallet-only users, and agent users all handled correctly
  • Build passes

Self-Verification (T3)

  • Run npm run dev, connect a NEW wallet (not in DB yet)
  • Simultaneously trigger register-by-wallet + onboard (connect wallet then immediately click Refresh Profile)
  • Check Supabase — verify user row is consistent (not duplicated, no mixed data)
  • Repeat 3 times — no 500 errors in server logs
  • Run npm run build — no errors
  • Run npm run typecheck — no type errors

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent/T3Assigned to T3 builder agent

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions