dotnet/eShop · error · RpcException
NotFound
NotFound
Error message
Basket with buyer id {userId} does not exist What it means
Thrown by BasketService.UpdateBasket via ThrowBasketDoesNotExist when IBasketRepository.UpdateBasketAsync returns null, i.e. the buyer's basket key was not found in the backing store (Redis). It is an RpcException with gRPC StatusCode.NotFound, signalling the client referenced a basket that does not exist. Note the exception is only raised from the UpdateBasket path; DeleteBasket silently no-ops on a missing basket.
Source
Thrown at src/Basket.API/Grpc/BasketService.cs:75
}
public override async Task<DeleteBasketResponse> DeleteBasket(DeleteBasketRequest request, ServerCallContext context)
{
var userId = context.GetUserIdentity();
if (string.IsNullOrEmpty(userId))
{
ThrowNotAuthenticated();
}
await repository.DeleteBasketAsync(userId);
return new();
}
[DoesNotReturn]
private static void ThrowNotAuthenticated() => throw new RpcException(new Status(StatusCode.Unauthenticated, "The caller is not authenticated."));
[DoesNotReturn]
private static void ThrowBasketDoesNotExist(string userId) => throw new RpcException(new Status(StatusCode.NotFound, $"Basket with buyer id {userId} does not exist"));
private static CustomerBasketResponse MapToCustomerBasketResponse(CustomerBasket customerBasket)
{
var response = new CustomerBasketResponse();
foreach (var item in customerBasket.Items)
{
response.Items.Add(new BasketItem()
{
ProductId = item.ProductId,
Quantity = item.Quantity,
});
}
return response;
}
private static CustomerBasket MapToCustomerBasket(string userId, UpdateBasketRequest customerBasketRequest)View on GitHub (pinned to 9b4f9434f4)
Solutions
- Call GetBasket first; if it returns empty, the basket does not exist yet — populate items and call UpdateBasket only after a basket exists (or rely on UpdateBasketAsync to create when the repository implementation supports upsert).
- Verify the Redis connection string and that the Redis data volume persists across container restarts.
- Confirm the buyerId supplied (from the token) matches the one used when the basket was originally stored.
- Handle the NotFound RpcException in the client and fall back to creating a fresh basket for the buyer.
Example fix
// before
var resp = await basketClient.UpdateBasketAsync(new UpdateBasketRequest { /* items */ });
// after
try {
var resp = await basketClient.UpdateBasketAsync(req, headers);
} catch (RpcException ex) when (ex.StatusCode == StatusCode.NotFound) {
// basket missing — re-initialise for this buyer then retry update
await basketClient.UpdateBasketAsync(req, headers);
} Defensive patterns
Strategy: try-catch
Validate before calling
var existing = await basketClient.GetBasketAsync(new GetBasketRequest(), headers); var exists = existing.Items.Count > 0 || /* or a server flag */ true; // see repository semantics // If your repository exposes an Exists check, call it before Update.
Type guard
static bool BasketLooksPresent(CustomerBasketResponse resp) => resp is not null; // empty response == not found in this API
Try / catch
try {
return await basketClient.UpdateBasketAsync(req, headers);
} catch (RpcException ex) when (ex.StatusCode == StatusCode.NotFound) {
// basket missing: create a fresh basket for the buyer, then retry the update
return await basketClient.UpdateBasketAsync(req, headers);
} Prevention
- Always establish the basket (via Get) before issuing Update.
- Persist Redis data on a volume so baskets survive restarts.
- Keep the buyerId stable across the basket lifecycle.
When it happens
Trigger: Calling UpdateBasket for a buyerId whose basket was never created, was already deleted, or expired from Redis before the update. Also reproduced if the Redis connection/data volume is non-persistent across restarts so previously created baskets vanish, or if the buyerId used by the client differs from the one under which the basket was stored.
Common situations: First basket action for a new user is Update instead of an initial Create/Get flow; Redis container lost its volume (dev/test restart); misconfigured Redis connection string pointing at a different instance; the IdentityServer-issued sub claim changed for the same human (re-issued identity) so the key no longer matches.
Related errors
AI-assisted analysis of dotnet/eShop@9b4f9434f4 (2026-08-13).
Data as JSON: /api/errors/8d536d7937889490.
Report an issue: GitHub.