GoogleCloudPlatform/microservices-demo · error

shipping quote failure: %+v

Error message

shipping quote failure: %+v

What it means

quoteShipping calls ShippingService.GetQuote over gRPC; any failure is wrapped as 'shipping quote failure' by prepareOrderItemsAndShippingQuoteFromCart. It means the checkout flow could not obtain a cost estimate for shipping the cart to the given address. The root cause lives in the shippingservice or the network path to it.

Source

Thrown at src/checkoutservice/main.go:300

type orderPrep struct {
	orderItems            []*pb.OrderItem
	cartItems             []*pb.CartItem
	shippingCostLocalized *pb.Money
}

func (cs *checkoutService) prepareOrderItemsAndShippingQuoteFromCart(ctx context.Context, userID, userCurrency string, address *pb.Address) (orderPrep, error) {
	var out orderPrep
	cartItems, err := cs.getUserCart(ctx, userID)
	if err != nil {
		return out, fmt.Errorf("cart failure: %+v", err)
	}
	orderItems, err := cs.prepOrderItems(ctx, cartItems, userCurrency)
	if err != nil {
		return out, fmt.Errorf("failed to prepare order: %+v", err)
	}
	shippingUSD, err := cs.quoteShipping(ctx, address, cartItems)
	if err != nil {
		return out, fmt.Errorf("shipping quote failure: %+v", err)
	}
	shippingPrice, err := cs.convertCurrency(ctx, shippingUSD, userCurrency)
	if err != nil {
		return out, fmt.Errorf("failed to convert shipping cost to currency: %+v", err)
	}

	out.shippingCostLocalized = shippingPrice
	out.cartItems = cartItems
	out.orderItems = orderItems
	return out, nil
}

func (cs *checkoutService) quoteShipping(ctx context.Context, address *pb.Address, items []*pb.CartItem) (*pb.Money, error) {
	shippingQuote, err := pb.NewShippingServiceClient(cs.shippingSvcConn).
		GetQuote(ctx, &pb.GetQuoteRequest{
			Address: address,
			Items:   items})
	if err != nil {

View on GitHub (pinned to 72ba613a05)

Solutions

  1. Inspect the wrapped gRPC error code in logs to distinguish unavailable vs invalid-argument vs deadline-exceeded.
  2. Check shippingservice health: kubectl get pods, logs, and restart it if crash-looping.
  3. Validate the shipping Address proto has non-empty fields before calling PlaceOrder.
  4. Increase or configure the gRPC/context timeout if deadline-exceeded occurs under load; verify service DNS/connections.

Example fix

// before
shippingUSD, err := cs.quoteShipping(ctx, address, cartItems)
if err != nil {
	return out, fmt.Errorf("shipping quote failure: %+v", err)
}
// after
shippingUSD, err := cs.quoteShipping(ctx, address, cartItems)
if err != nil {
	if status.Code(err) == codes.Unavailable {
		return out, status.Error(codes.Unavailable, "shipping service temporarily unavailable, retry checkout")
	}
	return out, fmt.Errorf("shipping quote failure: %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

if address == nil || address.GetStreetAddress() == "" {
	return status.Error(codes.InvalidArgument, "shipping address is required")
}
if len(cartItems) == 0 {
	return status.Error(codes.FailedPrecondition, "cart is empty")
}

Type guard

func hasValidAddress(a *pb.Address) bool {
	return a != nil && a.GetStreetAddress() != "" && a.GetCity() != "" && a.GetCountry() != ""
}

Try / catch

err := placeOrder(ctx, req)
if err != nil {
	if status.Code(err) == codes.Unavailable {
		// exponential backoff retry, e.g. 3 attempts
	}
	if status.Code(err) == codes.DeadlineExceeded {
		// increase timeout or shed load
	}
	return err
}

Prevention

When it happens

Trigger: pb.NewShippingServiceClient(cs.shippingSvcConn).GetQuote returns a gRPC error: shippingservice unavailable, deadline exceeded, invalid/empty address, or malformed cart items.

Common situations: shippingservice pod crashed or OOM-killed; connection pool to shippingservice broken after restart; empty Address proto passed by frontend; context deadline exceeded under load.

Related errors


AI-assisted analysis of GoogleCloudPlatform/microservices-demo@72ba613a05 (2026-09-02). Data as JSON: /api/errors/5a282eb1dc3eec8d. Report an issue: GitHub.