Skip to content

[Bug] Race condition in card creation — concurrent requests can create multiple default cards #333

@Midoriya-w

Description

@Midoriya-w

Summary

In apps/backend/src/routes/cards.ts, the POST /api/cards endpoint checks if the user has zero cards to decide whether the new card should be the default:

const cardCount = await app.prisma.card.count({ where: { userId } });

const card = await app.prisma.card.create({
  data: {
    isDefault: cardCount === 0,
    ...
  }
});

These are two separate database operations with no transaction or lock between them. If two requests arrive simultaneously when a user has zero cards, both will read cardCount === 0 and both will create a card with isDefault: true — leaving the user with two default cards.

Location

apps/backend/src/routes/cards.tsPOST / handler

Steps to Reproduce

  1. Send two simultaneous POST /api/cards requests for a new user with no existing cards
  2. Both requests read cardCount === 0
  3. Both cards are created with isDefault: true
  4. User now has two default cards data integrity violation

Fix

Wrap the count check and card creation in a single Prisma transaction to prevent the race window.

Impact

Data integrity violation user ends up with multiple default cards causing undefined behaviour in the UI.

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