🧩 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:
type Pricing struct {
Price int64 `json:"price,omitempty"`
PriceOff int64 `json:"priceOff,omitempty"`
DiscountPercent float32 `json:"discountPercent,omitempty"`
}And a conversion function:
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 / priceis integer division, and ifdiscountis smaller thanprice, the result is0.- Even though you cast the result to
float32, it happens after the truncation. Sofloat32(0)is still0.0. - Go’s JSON encoder sees
0.0and thanks toomitempty, omits the field.
✅ Solution: Embrace Floating Point Precision
Fix the division like this:
DiscountPercent: float32(discount) / float32(price)This way:
- You get proper floating-point division.
DiscountPercentreflects accurate values,0.0885instead 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.
