{"record":{"id":"6539bfa947f268e9","repo":"GoogleCloudPlatform/microservices-demo","slug":"failed-to-convert-shipping-cost-to-currency-v","errorCode":null,"errorMessage":"failed to convert shipping cost to currency: %+v","messagePattern":"failed to convert shipping cost to currency: %\\+v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/checkoutservice/main.go","lineNumber":304,"sourceCode":"}\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).\n\t\tGetQuote(ctx, &pb.GetQuoteRequest{\n\t\t\tAddress: address,\n\t\t\tItems:   items})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get shipping quote: %+v\", err)\n\t}\n\treturn shippingQuote.GetCostUsd(), nil\n}","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/GoogleCloudPlatform/microservices-demo/blob/72ba613a05f7fcee51cf1d0badff401b6ae7074d/src/checkoutservice/main.go#L286-L322","documentation":"convertCurrency calls CurrencyService.Convert; if the conversion of the shipping cost (originally USD) to the user's currency fails, this wrapper is emitted. It means the currency service rejected or could not process the conversion request. Only the shipping-cost conversion path raises this exact message (product-price conversion uses a different wrapper).","triggerScenarios":"CurrencyService.Convert returns an error for {from: shippingUSD, toCode: userCurrency}: unsupported target currency, empty Money struct, currencyservice unreachable, or the internal context.TODO() call timing out.","commonSituations":"User supplied a currency code not in the currency service's supported list; currencyservice deployment down; env var CURRENCY_SERVICE not wired so the connection points nowhere; load-induced gRPC deadline exceeded.","solutions":["Log the wrapped error and check its gRPC status code (Unavailable vs InvalidArgument).","Validate userCurrency is in currencyservice's supported currencies before checkout.","Check currencyservice pods/logs and restart if unhealthy.","Verify cs.currencySvcConn is dialed to the correct service address at startup.","Replace context.TODO() with the request ctx so cancellation/timeouts propagate."],"exampleFix":"// before\nresult, err := pb.NewCurrencyServiceClient(cs.currencySvcConn).Convert(context.TODO(), &pb.CurrencyConversionRequest{\n\tFrom:   from,\n\tToCode: toCurrency})\n// after\nresult, err := pb.NewCurrencyServiceClient(cs.currencySvcConn).Convert(ctx, &pb.CurrencyConversionRequest{\n\tFrom:   from,\n\tToCode: toCurrency})","handlingStrategy":"validation","validationCode":"supported, err := currencyClient.GetSupportedCurrencies(ctx, &emptypb.Empty{})\nif err != nil {\n\treturn err\n}\nif !slices.Contains(supported.GetCurrencyCodes(), userCurrency) {\n\treturn status.Error(codes.InvalidArgument, \"unsupported currency: \"+userCurrency)\n}","typeGuard":"func isConvertible(m *pb.Money, code string) bool {\n\treturn m != nil && m.GetCurrencyCode() != \"\" && code != \"\"\n}","tryCatchPattern":"shippingPrice, err := cs.convertCurrency(ctx, shippingUSD, userCurrency)\nif err != nil {\n\tif status.Code(err) == codes.InvalidArgument {\n\t\treturn status.Errorf(codes.InvalidArgument, \"cannot convert to %s\", userCurrency)\n\t}\n\treturn fmt.Errorf(\"failed to convert shipping cost to currency: %w\", err)\n}","preventionTips":["Whitelist currencies at the frontend","Never pass nil Money to Convert","Use the request context (not context.TODO) in conversions","Alert on currencyservice error rates"],"tags":["grpc","currency","microservices","conversion"],"backgroundTag":"currency-conversion-failed","analyzedSha":"72ba613a05f7fcee51cf1d0badff401b6ae7074d","analyzedAt":"2026-09-02T01:15:09.673Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}