{"record":{"id":"9ae2423cefab3c96","repo":"GoogleCloudPlatform/microservices-demo","slug":"failed-to-get-shipping-quote-v","errorCode":null,"errorMessage":"failed to get shipping quote: %+v","messagePattern":"failed to get shipping quote: %\\+v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/checkoutservice/main.go","lineNumber":319,"sourceCode":"\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}\n\nfunc (cs *checkoutService) getUserCart(ctx context.Context, userID string) ([]*pb.CartItem, error) {\n\tcart, err := pb.NewCartServiceClient(cs.cartSvcConn).GetCart(ctx, &pb.GetCartRequest{UserId: userID})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get user cart during checkout: %+v\", err)\n\t}\n\treturn cart.GetItems(), nil\n}\n\nfunc (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}","sourceCodeStart":301,"sourceCodeEnd":337,"githubUrl":"https://github.com/GoogleCloudPlatform/microservices-demo/blob/72ba613a05f7fcee51cf1d0badff401b6ae7074d/src/checkoutservice/main.go#L301-L337","documentation":"quoteShipping is the inner wrapper: the gRPC GetQuote call to shippingservice returned an error and is wrapped with 'failed to get shipping quote'. The shipping service prices a cart for a destination address; failure here blocks checkout. Error 21 is this error re-wrapped by the caller.","triggerScenarios":"pb.NewShippingServiceClient(cs.shippingSvcConn).GetQuote(ctx, &pb.GetQuoteRequest{Address, Items}) returns a non-nil error: unavailable service, invalid argument (nil/empty address or items), or deadline exceeded.","commonSituations":"Frontend sent an Address with empty fields; shippingservice restarted and the connection went stale; cross-service network policy blocked the port; sustained load causing context cancellation.","solutions":["Check the gRPC status code of the wrapped error to identify unavailable vs invalid-argument.","Validate the Address and Items are non-empty/valid before calling GetQuote.","Check shippingservice health and logs; restart crash-looping pods.","Ensure checkoutservice can resolve and reach shippingservice (DNS, network policies, correct port)."],"exampleFix":"// before\nshippingQuote, err := pb.NewShippingServiceClient(cs.shippingSvcConn).\n\tGetQuote(ctx, &pb.GetQuoteRequest{Address: address, Items: items})\nif err != nil {\n\treturn nil, fmt.Errorf(\"failed to get shipping quote: %+v\", err)\n}\n// after\nif address == nil || items == nil {\n\treturn nil, status.Error(codes.InvalidArgument, \"address and items are required for a shipping quote\")\n}\nshippingQuote, err := pb.NewShippingServiceClient(cs.shippingSvcConn).\n\tGetQuote(ctx, &pb.GetQuoteRequest{Address: address, Items: items})\nif err != nil {\n\treturn nil, fmt.Errorf(\"failed to get shipping quote: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"if !hasValidAddress(address) || len(items) == 0 {\n\treturn status.Error(codes.InvalidArgument, \"address and items required for quote\")\n}","typeGuard":"func hasValidAddress(a *pb.Address) bool {\n\treturn a != nil && a.GetStreetAddress() != \"\" && a.GetCountry() != \"\"\n}","tryCatchPattern":"shippingQuote, err := shippingClient.GetQuote(ctx, req)\nif err != nil {\n\tswitch status.Code(err) {\n\tcase codes.Unavailable:\n\t\treturn retryWithBackoff(ctx, req)\n\tcase codes.InvalidArgument:\n\t\treturn status.Error(codes.InvalidArgument, \"check address and cart items\")\n\tdefault:\n\t\treturn fmt.Errorf(\"failed to get shipping quote: %w\", err)\n\t}\n}","preventionTips":["Validate address/cart before the RPC","Configure gRPC client retries for transient codes","Use health checking (grpc_health_probe) between services","Log gRPC status codes, not just messages"],"tags":["grpc","shipping","rpc","microservices"],"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"}