{"record":{"id":"8d536d7937889490","repo":"dotnet/eShop","slug":"notfound","errorCode":"NotFound","errorMessage":"Basket with buyer id {userId} does not exist","messagePattern":"Basket with buyer id (.+?) does not exist","errorType":"exception","errorClass":"RpcException","httpStatus":null,"severity":"error","filePath":"src/Basket.API/Grpc/BasketService.cs","lineNumber":75,"sourceCode":"    }\n\n    public override async Task<DeleteBasketResponse> DeleteBasket(DeleteBasketRequest request, ServerCallContext context)\n    {\n        var userId = context.GetUserIdentity();\n        if (string.IsNullOrEmpty(userId))\n        {\n            ThrowNotAuthenticated();\n        }\n\n        await repository.DeleteBasketAsync(userId);\n        return new();\n    }\n\n    [DoesNotReturn]\n    private static void ThrowNotAuthenticated() => throw new RpcException(new Status(StatusCode.Unauthenticated, \"The caller is not authenticated.\"));\n\n    [DoesNotReturn]\n    private static void ThrowBasketDoesNotExist(string userId) => throw new RpcException(new Status(StatusCode.NotFound, $\"Basket with buyer id {userId} does not exist\"));\n\n    private static CustomerBasketResponse MapToCustomerBasketResponse(CustomerBasket customerBasket)\n    {\n        var response = new CustomerBasketResponse();\n\n        foreach (var item in customerBasket.Items)\n        {\n            response.Items.Add(new BasketItem()\n            {\n                ProductId = item.ProductId,\n                Quantity = item.Quantity,\n            });\n        }\n\n        return response;\n    }\n\n    private static CustomerBasket MapToCustomerBasket(string userId, UpdateBasketRequest customerBasketRequest)","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/dotnet/eShop/blob/9b4f9434f46fdc5c1a6e9e936af2868340cdbc48/src/Basket.API/Grpc/BasketService.cs#L57-L93","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nvar resp = await basketClient.UpdateBasketAsync(new UpdateBasketRequest { /* items */ });\n\n// after\ntry {\n    var resp = await basketClient.UpdateBasketAsync(req, headers);\n} catch (RpcException ex) when (ex.StatusCode == StatusCode.NotFound) {\n    // basket missing — re-initialise for this buyer then retry update\n    await basketClient.UpdateBasketAsync(req, headers);\n}","handlingStrategy":"try-catch","validationCode":"var existing = await basketClient.GetBasketAsync(new GetBasketRequest(), headers);\nvar exists = existing.Items.Count > 0 || /* or a server flag */ true; // see repository semantics\n// If your repository exposes an Exists check, call it before Update.","typeGuard":"static bool BasketLooksPresent(CustomerBasketResponse resp) => resp is not null; // empty response == not found in this API","tryCatchPattern":"try {\n    return await basketClient.UpdateBasketAsync(req, headers);\n} catch (RpcException ex) when (ex.StatusCode == StatusCode.NotFound) {\n    // basket missing: create a fresh basket for the buyer, then retry the update\n    return await basketClient.UpdateBasketAsync(req, headers);\n}","preventionTips":["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."],"tags":["grpc","not-found","basket-api","redis","state"],"backgroundTag":null,"analyzedSha":"9b4f9434f46fdc5c1a6e9e936af2868340cdbc48","analyzedAt":"2026-08-13T19:29:36.594Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}