You start a new project without auth, and you get exactly one screen. Its entire content is a single request to the Worker’s health endpoint, rendering whatever comes back.
Rename that endpoint in the Worker without editing the screen, and here is what the adopter sees on their very first page:
The worker says: unknown.
A 200. No error. No failed build. Nothing in a log. The first screen of their new project displays a word that is not a status, for a reason that appears nowhere on the page.
The path was written out four times
The health path is needed in four places: createBackend mounts the route, the CLI’s route allowlist keeps it worker-first, pithy deploy probes it after a release, and the bare home screen fetches it.
Until recently, each of those four wrote the string out.
There are two ways to handle that. You can add a check that compares the copies and fails when they drift — which watches the problem. Or you can remove the copies, so there is one exported constant and the template imports it.
The second is better and it is not close. A gate that compares four copies is a fifth thing to maintain, and it only ever tells you that somebody already made the mistake. Removing the duplication means the mistake has nowhere to live.
Names truncated against a limit that does not exist
The same lesson, from a different direction.
Pithy used to hold one number — 63 — and apply it to every namespace it writes a name into. The justification was that it is R2’s cap.
It is R2’s cap. It is not anybody else’s.
So every other name was being truncated against a limit that did not apply, and one was being cut by roughly a factor of eight below what the service actually allows. A binding named secrets-encryption-keys came out the other side as:
secrets-encryp-91c2e9Hashed for nothing. There was no limit to fit inside.
Why a mangled name is worse than ugly
Two reasons, and the second is the one that bites.
Teardown has to recompute it exactly. A generated name is not a label — it is an identifier that some later operation must reproduce character for character to find and remove the thing. Truncation logic is now load-bearing infrastructure.
You have to recognize it in a Cloudflare dashboard listing that cannot be filtered. Looking at an account with dozens of resources across three environments, secrets-encryp-91c2e9 is a puzzle. secrets-encryption-keys is an answer.
Every limit carries its source
The fix was not a better number. It was a table of numbers, one per namespace, each labeled with where it came from:
| source | meaning |
|---|---|
cloudflare | documented — limits page, OpenAPI schema, or wrangler’s own constant, verified on a date |
pithy | Cloudflare publishes no cap; this is our ceiling, chosen and stated as ours |
That second row is the honest part. Where no published limit exists, the constant does not pretend to be a platform fact. It says: we picked this, and here is where the line is drawn.
Marking the difference means you can tell which numbers are discoverable and which are decisions — and you can go and check the ones claiming to be documented, because they carry a verification date.
The pattern both share
A string in four places and a number applied to five namespaces are the same defect wearing different clothes.
In both cases the value was knowable in exactly one place and got copied to where it was used. In both cases the bug produced no error — a 200 with the wrong word, a name that is merely odd. And in both cases the fix was not vigilance. It was arranging for the wrong version to be unwritable.
There is a useful test in here. When you are about to add a check that compares two copies of something, ask whether you could instead have one copy. If you can, the check is a worse version of the fix, and it will outlive the problem it was written for.