Midterms 2026See who we think should earn your vote, based on our standardsThe guide →
WRITTEN IN PLAIN AMERICAN ENGLISH.
CLAY TRIBUNE.
Advertisement

What TLA+ Can and Can’t Check — And Why the Formal Verification Hype Is Overblown

TLA+ verifies concurrent systems beautifully, yet it cannot check reachability, step sequences, floating-point behavior, or hyperproperties.

By mitch·4 min read
A glowing circuit board symbolizing a complex concurrent system being verified by formal methods.

Boris Cherny, the man behind Claude Code, made a quiet announcement last week. He said that Opus had used TLA+ to find race conditions in code. Since then, everyone on the internet has been talking about formal verification. That’s the story, and it’s a good one — but it comes with a caveat. TLA+ is great at designing complex concurrent systems and making sure they’re bug-free. It is not a magic wand for everything.

How TLA+ Breaks Down a System

TLA+ works by dividing a system into a set of behaviors. Each behavior is a sequence of states, like “light one is green, then yellow, then red.” Inside each state, you can write simple boolean expressions: “Light four is green” or “All lights are red.” Then you add three temporal operators:

  1. []P (“always P”) is true if P holds in the current state and every future state.
  2. P' (“P prime”) is true if P holds in the next state.
  3. <>P (“eventually P”) is true if P holds in the current state or at least one future state.

These operators let you build invariants, which are properties that hold across every state of every behavior. For example, []P means P is true in every initial state, and then by definition it stays true in every future state. That’s a safety property — something bad never happens. Liveness is the opposite: “something good always happens.” It’s built around <>P, but <>P alone is usually too weak. Combinations like []<>P and <>[]P make the logic richer.

Advertisement

There are also other operators like ENABLED and <<A>>_v. Most of what TLA+ checks falls into invariants, action properties, and liveness. Refinement combines safety and liveness and is a whole topic unto itself.

The Properties TLA+ Cannot Check

The catch is that TLA+ can’t check properties it can’t even express. If you don’t know how to represent your property as a logical formula, TLA+ can’t help you. That’s not a flaw in TLA+ — it’s a limit of formal methods generally. If you can’t formalize the human notion of a bird, you can’t prove your app recognizes birds.

Some properties fall into this category. Reachability properties are one example. You can’t prove a game is winnable, or that P is reachable from every initial state, or that P is reachable from any state where Q is true. These are called reachability properties.

Another limit is specificity. TLA+ safety properties work on individual states or single steps. You can’t define a property over two or more steps, like “pressing delete and then undo gives you back the original state.” You can’t define properties on floating point operations or over real time — only logical time. Hyperproperties are another blind spot. You can’t define properties over a set of behaviors. For example, you can’t model phone hardware where you want to say something about how multiple behaviors interact.

The Core Limitation

The most interesting limit, according to the author, is implicit quantification. TLA+ properties are implicitly quantified over all behaviors. Checking []P means “for all behaviors, []P is true of that behavior’s initial state.” Any property TLA+ can check must be true for every individual behavior. That means you can’t say “there exists a behavior where P is true.”

That leaves out a lot. You can’t prove that P is possible, even if you don’t actually reach it. You can’t define properties over a set of behaviors. The author calls these hyperproperties.

Why This Matters Now

The excitement around TLA+ is understandable. Cherny’s announcement showed that a real tool can find real bugs. But the hype machine has a habit of swallowing caveats. The author worries that people are saying that formal methods will solve the problem of agentic software development once and for all. That’s nonsense.

The weaknesses of TLA+ are well documented. Correct designs don’t automatically translate into correct code. But this newsletter focuses on a different limitation: to verify a property, you need to have a property to verify. If you can’t express the property, no tool can check it.

The author is a long-time educator and advocate of TLA+. They are also a long-time advocate of level-headedness. The new euphoria worries them.

What to Take From This

The takeaway is not that TLA+ is useless. It’s that it is precise. Its limits are knowable. The properties it can’t check are the properties it can’t check — and that’s a strength, not a failure.

The author’s own position is playful and honest. They deliver on both the promise of the title: what TLA+ can check and what it can’t.

TLA+ is great at designing complex concurrent systems and making sure they’re bug-free. It is not a magic wand for everything. The best way to use it is to know what it does well and what it doesn’t touch.

One final note: the author is a long-time educator and advocate of TLA+. They are also a long-time advocate of level-headedness. Their worry is that the new euphoria around the tool is drowning out the caveats. That’s worth keeping in mind as the conversation continues.

Source material: “What TLA+ can and can't check,” buttondown.com.

The Notebook

Get the Notebook.

The day's best stories and every fresh verdict, in plain English, in your inbox by seven. One email a day, no more.

We send one note to confirm. Every issue has a one-click way out.

Advertisement

Leave a Reply

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

As an Amazon Associate, Clay Tribune earns from qualifying purchases.