🧩 Common Bug in Calculate: Understanding omitempty and Integer Division in Go

When building APIs in Go, developers often use the omitempty tag to produce clean JSON outputs. However, fields sometimes mysteriously vanish, particularly computed float values such as percentages. Let’s unpack a classic example that trips up even experienced devs.

🎯 The Scenario

You have a price structure like this:

go
type Pricing struct {
    Price int64 `json:"price,omitempty"`
    PriceOff int64 `json:"priceOff,omitempty"`
    DiscountPercent float32 `json:"discountPercent,omitempty"`
}

And a conversion function:

go
func calculate(r *Input) *output {
    discount := r.discount
    price := r.productPrice
    priceOff := price - discount
    return &output{
        Price: price, PriceOff: priceOff, DiscountPercent: float32(discount / price),
    }
}

The result? DiscountPercent mysteriously disappears in your JSON output—even when you expect a non-zero discount.

🕵️ Root Cause: Integer Division + omitempty

Let’s break it down:

  • discount / price is integer division, and if discount is smaller than price, the result is 0.
  • Even though you cast the result tofloat32, it happens after the truncation. So float32(0) is still 0.0.
  • Go’s JSON encoder sees 0.0 and thanks to omitempty, omits the field.

✅ Solution: Embrace Floating Point Precision

Fix the division like this:

go
DiscountPercent: float32(discount) / float32(price)

This way:

  • You get proper floating-point division.
  • DiscountPercent reflects accurate values, 0.0885 instead of vanishing into thin air.

🔍 Why This Matters

These bugs aren’t flashy, but they undermine your data integrity. Fields that seem “missing” lead to confusion on the frontend and unnecessary debugging time. By paying attention to type behavior and encoding nuances, you maintain a solid and predictable API.

So next time you see a suspiciously absent field in your JSON, don’t blame the compiler. It’s probably just omitempty quietly doing its job... too well.