{"record":{"id":"bde57489f9d7d1f2","repo":"GoogleCloudPlatform/microservices-demo","slug":"failed-to-prepare-order-v","errorCode":null,"errorMessage":"failed to prepare order: %+v","messagePattern":"failed to prepare order: %\\+v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/checkoutservice/main.go","lineNumber":296,"sourceCode":"\tresp := &pb.PlaceOrderResponse{Order: orderResult}\n\treturn resp, nil\n}\n\ntype orderPrep struct {\n\torderItems            []*pb.OrderItem\n\tcartItems             []*pb.CartItem\n\tshippingCostLocalized *pb.Money\n}\n\nfunc (cs *checkoutService) prepareOrderItemsAndShippingQuoteFromCart(ctx context.Context, userID, userCurrency string, address *pb.Address) (orderPrep, error) {\n\tvar out orderPrep\n\tcartItems, err := cs.getUserCart(ctx, userID)\n\tif err != nil {\n\t\treturn out, fmt.Errorf(\"cart failure: %+v\", err)\n\t}\n\torderItems, err := cs.prepOrderItems(ctx, cartItems, userCurrency)\n\tif err != nil {\n\t\treturn out, fmt.Errorf(\"failed to prepare order: %+v\", err)\n\t}\n\tshippingUSD, err := cs.quoteShipping(ctx, address, cartItems)\n\tif err != nil {\n\t\treturn out, fmt.Errorf(\"shipping quote failure: %+v\", err)\n\t}\n\tshippingPrice, err := cs.convertCurrency(ctx, shippingUSD, userCurrency)\n\tif err != nil {\n\t\treturn out, fmt.Errorf(\"failed to convert shipping cost to currency: %+v\", err)\n\t}\n\n\tout.shippingCostLocalized = shippingPrice\n\tout.cartItems = cartItems\n\tout.orderItems = orderItems\n\treturn out, nil\n}\n\nfunc (cs *checkoutService) quoteShipping(ctx context.Context, address *pb.Address, items []*pb.CartItem) (*pb.Money, error) {\n\tshippingQuote, err := pb.NewShippingServiceClient(cs.shippingSvcConn).","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/GoogleCloudPlatform/microservices-demo/blob/72ba613a05f7fcee51cf1d0badff401b6ae7074d/src/checkoutservice/main.go#L278-L314","documentation":"prepareOrderItemsAndShippingQuoteFromCart wraps any error from prepOrderItems (which fetches products from the product catalog and converts their prices) with this message before bubbling it up to PlaceOrder. It is a pass-through wrapper: the root cause is always a downstream product-catalog or currency-conversion failure. The %+v verb unwraps the wrapped error chain for diagnostics.","triggerScenarios":"prepOrderItems fails because ProductCatalogService.GetProduct returns an error for one of the cart item IDs (unknown/missing product, catalog RPC failure), or convertCurrency fails for a product price (currency service down, unsupported currency code).","commonSituations":"Stale cart entries pointing at product IDs that no longer exist in the catalog; product-catalog service crashed or unreachable in Kubernetes; user currency code unsupported by the currency service; network policy blocking checkout->catalog gRPC traffic.","solutions":["Check the wrapped error: if it is 'failed to get product', verify the product ID exists via ProductCatalogService.ListProducts.","Ensure the productcatalogservice deployment is healthy: kubectl get pods, check its logs and readiness probes.","Verify the user's currency code is one supported by currencyservice (see pb getSupportedCurrencies).","Confirm network policies/DNS allow checkoutservice to reach productcatalogservice and currencyservice on gRPC ports."],"exampleFix":"// before\norderItems, err := cs.prepOrderItems(ctx, cartItems, userCurrency)\nif err != nil {\n\treturn out, fmt.Errorf(\"failed to prepare order: %+v\", err)\n}\n// after\norderItems, err := cs.prepOrderItems(ctx, cartItems, userCurrency)\nif err != nil {\n\tlog.Printf(\"prepOrderItems failed for user %s: %v\", userID, err)\n\treturn out, fmt.Errorf(\"failed to prepare order: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"// Go: validate cart and currency before calling PlaceOrder\nif len(cartItems) == 0 {\n\treturn status.Error(codes.FailedPrecondition, \"cart is empty\")\n}\nif !isSupportedCurrency(userCurrency) {\n\treturn status.Error(codes.InvalidArgument, \"unsupported currency: \"+userCurrency)\n}","typeGuard":"func isSupportedCurrency(code string) bool {\n\tfor _, c := range supportedCurrencies { // fetched from currencyservice at startup\n\t\tif c == code {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}","tryCatchPattern":"orderItems, err := cs.prepareOrderItemsAndShippingQuoteFromCart(ctx, order, userID, userCurrency, address)\nif err != nil {\n\tvar gerr *grpcStatusError\n\tif errors.As(err, &gerr) && status.Code(gerr) == codes.Unavailable {\n\t\t// retry with backoff or return 503\n\t}\n\treturn fmt.Errorf(\"checkout failed: %w\", err)\n}","preventionTips":["Validate cart item IDs against the catalog before checkout","Verify the target currency is supported before conversion","Keep gRPC connections health-checked; enable retry policy on the channel","Wrap errors with %w so root causes stay visible in logs"],"tags":["grpc","microservices","checkout","error-wrapping"],"backgroundTag":"downstream-grpc-call-failed","analyzedSha":"72ba613a05f7fcee51cf1d0badff401b6ae7074d","analyzedAt":"2026-09-02T01:15:09.673Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}