Skip to content

Username Claim Race Condition Leaks Prisma P2002 as 500 #227

@Ridanshi

Description

@Ridanshi

Summary

The username update flow performs a read-before-write uniqueness check without handling concurrent update races.

Under simultaneous requests, Prisma unique constraint violations leak as internal 500 errors instead of deterministic conflict responses.


Affected File

apps/backend/src/routes/profiles.ts


Root Cause

The current flow performs:

const existing = await app.prisma.user.findFirst({
  where: {
    username,
    NOT: { id: userId }
  }
});

if (existing) {
  return reply.status(409).send(...);
}

followed later by:

await app.prisma.user.update(...)

This creates a classic check-then-act race window.

Two concurrent requests can:

  1. both pass the uniqueness check,
  2. both attempt the update,
  3. and cause the database unique constraint to fail on one request.

The resulting Prisma P2002 exception is currently unhandled.


Impact

Affected users receive:

  • unexpected 500 responses,
  • inconsistent username-update behavior,
  • and potential Prisma error leakage in development environments.

This becomes realistic under:

  • double-submit behavior,
  • client retries,
  • aggressive mobile reconnection flows,
  • or concurrent browser requests.

Reproduction

Send two concurrent profile update requests attempting to claim the same username.

Expected:

One succeeds,
one returns 409 Conflict

Actual:

One succeeds,
one throws unhandled Prisma P2002 → 500 Internal Server Error

Proposed Fix

Wrap the update flow in proper Prisma error handling.

Suggested approach:

try {
  await app.prisma.user.update(...)
} catch (err: any) {
  if (err.code === 'P2002') {
    return reply.status(409).send(...);
  }

  throw err;
}

This preserves deterministic conflict handling even under concurrent writes.


Acceptance Criteria

  • Concurrent username claims never produce 500 errors.
  • Prisma P2002 conflicts return 409 responses.
  • Existing username validation behavior remains unchanged.
  • Race conditions are handled gracefully.

Severity

Medium

This is a realistic concurrency flaw affecting username uniqueness enforcement and API reliability.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions