{"record":{"id":"415aef4e5e36b59e","repo":"GoogleCloudPlatform/microservices-demo","slug":"failed-to-convert-price-of-q-to-s","errorCode":null,"errorMessage":"failed to convert price of %q to %s","messagePattern":"failed to convert price of %q to (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/checkoutservice/main.go","lineNumber":350,"sourceCode":"func (cs *checkoutService) emptyUserCart(ctx context.Context, userID string) error {\n\tif _, err := pb.NewCartServiceClient(cs.cartSvcConn).EmptyCart(ctx, &pb.EmptyCartRequest{UserId: userID}); err != nil {\n\t\treturn fmt.Errorf(\"failed to empty user cart during checkout: %+v\", err)\n\t}\n\treturn nil\n}\n\nfunc (cs *checkoutService) prepOrderItems(ctx context.Context, items []*pb.CartItem, userCurrency string) ([]*pb.OrderItem, error) {\n\tout := make([]*pb.OrderItem, len(items))\n\tcl := pb.NewProductCatalogServiceClient(cs.productCatalogSvcConn)\n\n\tfor i, item := range items {\n\t\tproduct, err := cl.GetProduct(ctx, &pb.GetProductRequest{Id: item.GetProductId()})\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to get product #%q\", item.GetProductId())\n\t\t}\n\t\tprice, err := cs.convertCurrency(ctx, product.GetPriceUsd(), userCurrency)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to convert price of %q to %s\", item.GetProductId(), userCurrency)\n\t\t}\n\t\tout[i] = &pb.OrderItem{\n\t\t\tItem: item,\n\t\t\tCost: price}\n\t}\n\treturn out, nil\n}\n\nfunc (cs *checkoutService) convertCurrency(ctx context.Context, from *pb.Money, toCurrency string) (*pb.Money, error) {\n\tresult, err := pb.NewCurrencyServiceClient(cs.currencySvcConn).Convert(context.TODO(), &pb.CurrencyConversionRequest{\n\t\tFrom:   from,\n\t\tToCode: toCurrency})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to convert currency: %+v\", err)\n\t}\n\treturn result, err\n}\n","sourceCodeStart":332,"sourceCodeEnd":368,"githubUrl":"https://github.com/GoogleCloudPlatform/microservices-demo/blob/72ba613a05f7fcee51cf1d0badff401b6ae7074d/src/checkoutservice/main.go#L332-L368","documentation":"After fetching the product, prepOrderItems converts its USD price to the user's currency via convertCurrency; failure is wrapped with the product ID and target currency. The underlying error is again swallowed, hiding whether the cause was an unsupported currency or a currency-service outage.","triggerScenarios":"cs.convertCurrency(ctx, product.GetPriceUsd(), userCurrency) errors: userCurrency not supported by currencyservice, Money struct empty/zero, or currencyservice unavailable/deadline exceeded.","commonSituations":"Client sends a currency code (e.g. 'GBP ') with wrong case or whitespace not in the supported list; currencyservice down; currency conversion config/env changed after a deploy.","solutions":["Log the wrapped error with %w to expose the real cause.","Validate userCurrency against currencyservice's supported currency list before checkout.","Check currencyservice pods/logs and connectivity from checkoutservice.","Confirm the product's PriceUsd is populated (not nil/zero) in catalog data."],"exampleFix":"// before\nprice, err := cs.convertCurrency(ctx, product.GetPriceUsd(), userCurrency)\nif err != nil {\n\treturn nil, fmt.Errorf(\"failed to convert price of %q to %s\", item.GetProductId(), userCurrency)\n}\n// after\nprice, err := cs.convertCurrency(ctx, product.GetPriceUsd(), userCurrency)\nif err != nil {\n\treturn nil, fmt.Errorf(\"failed to convert price of %q to %s: %w\", item.GetProductId(), userCurrency, err)\n}","handlingStrategy":"validation","validationCode":"if !isSupportedCurrency(userCurrency) {\n\treturn status.Error(codes.InvalidArgument, \"unsupported currency: \"+userCurrency)\n}\nif product.GetPriceUsd() == nil {\n\treturn status.Error(codes.FailedPrecondition, \"product price missing\")\n}","typeGuard":"func isConvertiblePrice(m *pb.Money) bool {\n\treturn m != nil && m.GetUnits() >= 0 && m.GetCurrencyCode() == \"USD\"\n}","tryCatchPattern":"price, err := cs.convertCurrency(ctx, product.GetPriceUsd(), userCurrency)\nif err != nil {\n\tif status.Code(err) == codes.InvalidArgument {\n\t\treturn fmt.Errorf(\"currency %s not supported: %w\", userCurrency, err)\n\t}\n\treturn fmt.Errorf(\"failed to convert price to %s: %w\", userCurrency, err)\n}","preventionTips":["Restrict the currency selector to supported codes","Never swallow the wrapped error — use %w","Check currencyservice health before checkout-heavy periods","Validate catalog prices are populated"],"tags":["grpc","currency","conversion","microservices"],"backgroundTag":"currency-conversion-failed","analyzedSha":"72ba613a05f7fcee51cf1d0badff401b6ae7074d","analyzedAt":"2026-09-02T01:15:09.673Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}