Plate № 06 · Cloudflare gotchas

A pattern from the gf.cx specimen book

Workers-with-Assets · run_worker_first

Source · Dan, 2026-05-28

"Default routes browser navigations through the assets-layer FIRST, bypassing the Worker. curl works, browser 404s. Should bake into gfcx_subdomain_new.py template."

The problem

A Cloudflare Pages project with a _worker.ts + assets binding looks like it should serve dynamic routes from the Worker and static files from the asset layer. In practice, browser navigations (requests with Sec-Fetch-Mode: navigate) route through the asset layer first, returning a 404 for routes the Worker would have handled. The symptom: curl returns 200, the browser returns 404. Easy to misdiagnose as DNS, cache, or routing.

The fix

# wrangler.toml — every new gf.cx subdomain serving both static + API
[assets]
directory = "./dist"
binding = "ASSETS"
run_worker_first = true   # ← Worker gets first crack at every request

Where it applies

How to recognise

If curl https://name.gf.cx/dynamic-route returns 200 and the same URL in a browser returns 404, with the response showing cf-cache-status: MISS or no Worker invocation log: this is the bug.

Reusable elements

The named, copyable pieces — lift any one without the others:

Reference

Source
Dan, 2026-05-28.
In use / example
sandbox.gf.cx — its Workers-with-Assets migration on 2026-05-27 surfaced this exact trap a second time (the first hit was dare.co.uk/ip), proving the pattern travels across surfaces.
Reusable elements
run_worker_first = true config · cf-cache-status diagnostic header · scaffold default in gfcx_subdomain_new.py (listed above).
Build cost
90 minutes on dare.co.uk/ip before the cf-cache-status HIT/MISS signal broke the diagnosis open. The curl-works-browser-404 symptom is easy to misread as DNS, cache, or routing until you see that header.