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:
- both pass the uniqueness check,
- both attempt the update,
- 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.
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.tsRoot Cause
The current flow performs:
followed later by:
This creates a classic check-then-act race window.
Two concurrent requests can:
The resulting Prisma
P2002exception is currently unhandled.Impact
Affected users receive:
This becomes realistic under:
Reproduction
Send two concurrent profile update requests attempting to claim the same username.
Expected:
Actual:
Proposed Fix
Wrap the update flow in proper Prisma error handling.
Suggested approach:
This preserves deterministic conflict handling even under concurrent writes.
Acceptance Criteria
P2002conflicts return 409 responses.Severity
Medium
This is a realistic concurrency flaw affecting username uniqueness enforcement and API reliability.