dotnet/eShop · warning · OrderingDomainException

Request with {id} already exists

Error message

Request with {id} already exists

What it means

Thrown by RequestManager.CreateRequestForCommandAsync when a ClientRequest row with the given Guid id already exists. RequestManager implements the idempotency pattern: each command carries a unique request id, and the first time it is processed a ClientRequest is recorded. A second attempt with the same id is treated as a duplicate and rejected with an OrderingDomainException before the handler runs.

Source

Thrown at src/Ordering.Infrastructure/Idempotency/RequestManager.cs:26

    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }


    public async Task<bool> ExistAsync(Guid id)
    {
        var request = await _context.
            FindAsync<ClientRequest>(id);

        return request != null;
    }

    public async Task CreateRequestForCommandAsync<T>(Guid id)
    {
        var exists = await ExistAsync(id);

        var request = exists ?
            throw new OrderingDomainException($"Request with {id} already exists") :
            new ClientRequest()
            {
                Id = id,
                Name = typeof(T).Name,
                Time = DateTime.UtcNow
            };

        _context.Add(request);

        await _context.SaveChangesAsync();
    }
}

View on GitHub (pinned to 9b4f9434f4)

Solutions

  1. Treat this exception as expected for duplicate delivery: catch OrderingDomainException from CreateRequestForCommandAsync and return the previously-completed result (or ack) instead of erroring — the work was already done.
  2. Generate a fresh request id per logical command attempt on the client, and only reuse the id when deliberately retrying the SAME command for idempotency.
  3. Ensure integration tests truncate/clear the ClientRequests table or use unique ids per run.
  4. Verify the queue/dead-letter config is not redelivering long-after the command succeeded.

Example fix

// before
await _requestManager.CreateRequestForCommandAsync<CreateOrderCommand>(id);
await _mediator.Send(command);

// after
try {
    await _requestManager.CreateRequestForCommandAsync<CreateOrderCommand>(id);
} catch (OrderingDomainException) {
    return; // duplicate delivery — command already processed, idempotent ack
}
await _mediator.Send(command);
Defensive patterns

Strategy: try-catch

Validate before calling

if (await requestManager.ExistAsync(id)) {
    // duplicate delivery — skip processing, return prior result
    return;
}

Type guard

static bool IsDuplicateRequest(bool exists) => exists;

Try / catch

try {
    await requestManager.CreateRequestForCommandAsync<CreateOrderCommand>(id);
} catch (OrderingDomainException) {
    // command already handled on a previous delivery — ack/idempotent return
    return;
}

Prevention

When it happens

Trigger: The same command (same request id) is dispatched more than once — e.g. a client retry, a message-broker redelivery, or a saga re-sending. CreateRequestForCommandAsync is called by a CreateOrderCommandHandler behavior that checks ExistAsync first; on a hit it throws, preventing duplicate order creation.

Common situations: gRPC/HTTP client retrying on timeout after the server already processed the command; message queue redelivering the integration event; integration tests reusing a fixed request id across runs without clearing the Request table; a network blip causing the client to resend.

Related errors


AI-assisted analysis of dotnet/eShop@9b4f9434f4 (2026-08-13). Data as JSON: /api/errors/8dd1c6bc8cbbd6a2. Report an issue: GitHub.