Somewhere in our billing flow, a single, well-intentioned .title() call decided to make things look nice. It did not break the build. It did not throw an error. It did something far more sinister: it returned 400 Bad Request to paying customers trying to upgrade, and it took us a while to figure out why.
The cast of characters
We have three plan tokens that travel end-to-end — frontend → createBillingCheckout → backend BillingCheckoutRequest:
coregrowthcore_sla
They are lowercase. They are meant to stay lowercase. They are, in essence, identifiers — not prose.
The crime
Somewhere, someone (it’s always someone) ran the plan token through title-casing to make it presentable in a label, and that “presentable” value leaked into the value sent to the backend:
"core_sla".replace(/_/g, " ") // "core sla"
// ...title-cased for display... // "Core Sla"Watch what happens to our carefully distinct tokens:
| Original | After “make it pretty” | Backend sees |
|---|---|---|
core | Core | core ✅ (lucky) |
growth | Growth | growth ✅ (lucky) |
core_sla | Core Sla | ❌ not a valid token |
The single most important plan — core_sla, the one with the SLA guarantee, the premium tier, the one that makes money — got mangled. Its distinguishing _sla suffix collapsed in the cosmetic wash, and the self-serve upgrade guard rejected it with a 400. Customers who wanted to give us more money were told, essentially, “no thank you, that plan doesn’t exist.”
Core and core_sla looked similar enough to a human and identical enough after title-casing to become indistinguishable. Capitalization, it turns out, is not a free aesthetic upgrade when the string is load-bearing.
The fix
Keep identifiers as identifiers, all the way down:
// the token stays lowercase, end to end
const planToken = "core_sla"; // never .title(), never prettified in transit
createBillingCheckout({ plan: planToken });If you want a pretty label for the UI, derive it separately and never send the pretty version back to the server:
const LABELS = { core: "Core", growth: "Growth", core_sla: "Core + SLA" };
// display LABELS[planToken]; transmit planTokenIt’s now a documented house rule: billing plan tokens stay lowercase end-to-end.
The moral
- Display strings and identifiers are different species. The moment you let a display transform touch a value that gets compared, looked up, or validated, you’ve planted a bug with a delay fuse.
- Lossy transforms (
.title(),.toLowerCase()on the wrong thing, trimming, slug-ifying) are especially dangerous on near-identical keys, because the failure only shows up on the one key that loses information. - The scariest bugs don’t crash. They return a confident
400and let you assume the customer did something wrong.
A capital C nearly cost us our best-margin plan. Respect your strings. Some of them have jobs.
Amit Jethva is the CTO and co-founder of Nuvika Technologies Pvt Ltd, makers of Fintropy, a multi-cloud FinOps platform. Learn more at nuvikatech.com.
