Idempotency & Error Handling
Relevant source files
The following files were used as context for generating this wiki page:
Introduction
The Dreamcats project implements a robust system for idempotency and error handling to ensure consistent game state across distributed clients. Given the real-time nature of the multiplayer card game, the system must handle network glitches, stale versions, and duplicate requests gracefully.
The architecture relies on Convex for backend state synchronization, utilizing unique idempotency keys to prevent double-application of game moves and sophisticated retry logic on the frontend to manage transient failures. This ensures that even if a response is lost, retrying an action will not result in multiple card draws or incorrect turn advancement.
Sources: AGENTS.md, src/state/useGame.ts:16-18
Idempotency System
Idempotency is enforced primarily at the database level through the moves and games tables. Every significant game action can be accompanied by an idempotencyKey, which uniquely identifies a specific intent from a client.
Strong Idempotency Logic
When performAction is called with an idempotencyKey, the server first queries the moves table to see if a record with that key already exists. If a prior result is found, the server returns the previous payload instead of re-executing the logic.
Sources: convex/actions.ts:24-40, convex/schema.ts:50-58
The flow above illustrates how the system intercepts duplicate requests to prevent redundant state mutations.
Sources: convex/actions.ts:24-40, convex/tests/actions-errors-and-idempotency.test.ts:110-140
Key Data Structures
The following fields in the schema support the idempotency and consistency framework:
| Table | Field | Type | Description |
|---|---|---|---|
games | version | number | Monotonically increasing version to avoid stale writes. |
games | idempotencyKey | string | Stores the key of the most recent successful mutation. |
moves | idempotencyKey | string | Primary index for checking duplicate actions. |
moves | payload | any | Stores the result/response of the original action. |
| Sources: convex/schema.ts:40-60 |
Error Handling
Error handling is distributed between backend validation and frontend retry/notification logic.
Server-Side Validation
The backend validates incoming actions against the current game phase and player turn. If validation fails, an error is thrown, which prevents the database transaction from committing.
Sources: convex/actions.ts:43-100
Key validation checks include:
- Phase Validation: Ensuring an action like
DRAW_FROM_DECKonly occurs during theplayingphase. - Turn Validation: verifying that the
playerIdmatches thecurrentPlayerIndex. - Resource Constraints: Checking if the deck has enough cards before starting a round.
Sources: convex/actions.ts:230-240, convex/tests/actions-errors-and-idempotency.test.ts:75-100
Client-Side Retry Strategy
The useGame hook implements a retryMutation utility that uses exponential backoff. It distinguishes between transient network errors and terminal logic errors.
Retriable errors
generally include network timeouts or glitches, while non-retriable errors include logic violations such as "Not your turn" or "Invalid card index."
Sources: src/state/useGame.ts:31-64
UX Notifications
The application uses sonner toast notifications to surface errors to the user. For online mutations, the system guards against:
- Stale Versions: Handled by Convex's optimistic concurrency control.
- Network Glitches: Gracefully handled by surfacing the error and allowing reconnection.
Sources: AGENTS.md, src/state/useGame.ts:145-155
State Consistency
To prevent stale state updates, the games table uses a version field. Every successful patch to the game state increments this version.
Sources: convex/actions.ts:58-64, convex/schema.ts:44
This sequence ensures that every mutation is recorded with its associated idempotency key, allowing subsequent retries to be resolved without further DB writes.
Sources: convex/actions.ts:43-65, convex/actions.ts:544-555
Summary
The "Idempotency & Error Handling" system provides a resilient foundation for the Dreamcats multiplayer experience. By combining unique action keys on the server with intelligent retry logic and exponential backoff on the client, the project maintains high data integrity even in unstable network conditions. Error surfacing via toasts ensures players are informed of terminal logic errors while the background system handles transient connectivity issues automatically.