Skip to content
José da Cruz

Enterprise Architect, and Life Thinker

José da Cruz

Enterprise Architect, and Life Thinker

Postel’s Law: Why Being Liberal in What You Accept Usually Backfires

josedacruz, September 24, 2026September 24, 2026

TL;DR: Postel’s Law — “be conservative in what you send, liberal in what you accept” — gets quoted as an excuse to skip validation on your API inputs. In practice, that habit doesn’t make your system more resilient; it just moves the failure further downstream, where it’s harder to trace and easier to exploit. Validate strictly at the boundary, reject clearly and immediately, and save your “liberal” energy for things like accepting multiple content-types or tolerating extra fields — not for tolerating garbage.

Postel’s Law comes from a 1980 note on the early TCP spec, written by Jon Postel: “be conservative in what you do, be liberal in what you accept from others.” It was meant to help independently-built network implementations talk to each other despite small differences in how they read the spec. Decades later, it got adopted as a general API design mantra, usually shortened to “accept anything, be strict about what you send.” That shortened version is where most of the trouble starts.

Let’s walk through the myths that keep this advice circulating, and what actually holds up once you’ve been on call for the system that took it too literally.

Myth: “Liberal in what you accept” means your API should tolerate malformed input

This is the most common misreading. People take it to mean: if a client sends a broken date, a missing field, or a number as a string, just do your best to make sense of it and carry on. In reality, Postel was talking about tolerating small, harmless variations between implementations of the same protocol — not about silently accepting data that doesn’t match the contract at all. There’s a big difference between “this timestamp has a few extra digits of precision, I can still parse it” and “this field is missing entirely, so I’ll just guess a default.” The first is tolerance. The second is your API quietly making decisions on behalf of a caller who doesn’t know it’s happening.

Myth: Being liberal makes your system more resilient

Here’s a concrete example. Imagine a small team building a payments API. Early on, someone notices that some client libraries send transaction timestamps as Unix seconds, some send milliseconds, and one partner integration sends full ISO 8601 strings. Instead of rejecting the two “wrong” formats, an engineer adds a bit of guessing logic: if the number looks too big to be seconds, treat it as milliseconds. It ships, nobody complains, and it feels like a resilience win.

Eight months later, a new partner sends timestamps in seconds, but for transactions dated far enough in the future that the “too big, must be milliseconds” heuristic misfires. Transactions get silently logged with wrong dates. Nobody notices until finance reconciliation flags a batch of records that don’t match the bank’s timeline. The bug isn’t in the guessing code itself — it’s in the fact that guessing was allowed to happen at all, invisibly, at the system boundary. A system that rejected the ambiguous input immediately would have forced the partner to fix their integration in week one, not month eight. Tolerance didn’t prevent a failure; it postponed it and made it more expensive.

Myth: Strict validation is unfriendly to your API’s clients

It feels polite to accept whatever a client sends and “just handle it.” But think about what actually happens from the client developer’s point of view in each case. With strict validation, they send a bad request, get a 400 response back immediately with a clear error message (“timestamp must be ISO 8601”), fix it in a few minutes, and move on. With liberal acceptance, their bad request succeeds. There’s no error. Weeks later, something downstream breaks in a way that has nothing obviously to do with the original mistake, and they spend a day debugging a system they don’t own to find a bug that was theirs the whole time. Fast, clear rejection at the door is kinder than silent corruption discovered later. It just doesn’t feel that way in the moment you’re writing the validation code, because rejecting things feels like friction and accepting things feels like helpfulness.

Radar chart comparing liberal acceptance and strict rejection across interoperability, debuggability, security, predictability, and dev speed
Liberal acceptance wins on short-term dev speed. Strict rejection wins on almost everything that matters once the system is actually running in production.

Myth: Postel’s Law is a timeless, universal principle for all system design

It’s worth remembering the context it came from: early network protocols, written by a small number of cooperating engineers, where the goal was getting independent implementations to interoperate at all. That’s a very different world from a public-facing API today, where “being liberal” about malformed input is also an attack surface. A parser that tries hard to make sense of weird input is a parser that has more edge cases, more code paths, and more chances for a security bug. This is part of why, years later, some of the same protocol engineers who worked in that world pushed back on treating the robustness principle as gospel — an IETF draft literally titled “The Harmful Consequences of the Robustness Principle” makes the case that liberal acceptance encourages senders to cut corners, because bad behavior keeps working. If everyone tolerates slightly-wrong input, slightly-wrong input becomes the norm, and now your “liberal” parser has to keep tolerating it forever, because Hyrum’s Law kicks in: enough callers are now depending on your forgiving behavior that you can’t tighten it without breaking someone.

Myth: You can’t be strict without breaking real-world interoperability

The fix isn’t to swing to the opposite extreme and reject anything that isn’t byte-for-byte perfect. It’s to be deliberate about where flexibility actually helps versus where it just hides bugs. A well-designed API can accept multiple content-types, tolerate unknown extra fields in a JSON body (ignoring them is genuinely useful for forward compatibility), and support versioned endpoints — all without ever guessing at malformed core data. Combine that with a published schema, contract tests between your API and its major clients, and clear versioning, and you get real interoperability without the ambiguity tax. The flexibility is intentional and documented, not an accidental side effect of validation code that gave up.

The rule of thumb: be liberal about format and structure where multiple valid forms genuinely exist and you can normalize them safely and visibly. Be strict about correctness — required fields, valid ranges, unambiguous types — and reject those failures loudly, immediately, and at the boundary. If you find yourself writing a comment like “probably means…” next to a parsing branch, that’s not resilience. That’s a bug you’ve agreed to ship on a schedule of your caller’s choosing.

Related

architecture API Designheuristicspostel's lawrobustness principlevalidation

Post navigation

Previous post
Next post

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

  • architecture (154)
  • artificial-intelligence (6)
  • books (2)
  • courses (4)
  • decision-frameworks (4)
  • finances (1)
  • java (8)
  • life-improvement (20)
  • metrics (3)
  • observability (2)
  • puzzles and challenges (3)
  • reviews (1)
  • security (8)
  • spring-boot (36)
  • Systems Thinking (3)
  • GitHub Weekly: MCP Tools Trending Right Now (September 28 – October 4, 2026)
  • The Bulkhead Pattern: Why One Slow Dependency Shouldn’t Sink the Whole Ship
  • Essential Reading: A Philosophy of Software Design — Fighting Complexity One Module at a Time
  • GitHub Weekly: Top 10 Trending Repos (September 21 – September 27, 2026)
  • The Volunteer Tax: Why Raising Your Hand in a Meeting Makes You the Permanent Owner
©2026 José da Cruz | WordPress Theme by SuperbThemes