Per-entrypoint Workers Cache does not intercept ctx.exports.<Entrypoint>.fetch() loopbacks (routing correct, placement off, config verified)
Summary
With the new per-entrypoint Workers Cache (launched 2026-07-06), a cached named WorkerEntrypoint invoked via ctx.exports.<Name>.fetch() from the default entrypoint is routed correctly but the cache layer never engages. The callee runs on every request, Cf-Cache-Status is never set on the loopback response, and Cache-Tag is never stripped — the platform's own signal that the response never transited the cache.
This appears distinct from #6215: in my case the fetch is not misrouted (it reaches the correct entrypoint), and Smart Placement is disabled. The cache simply is not sitting in front of the entrypoint.
Environment
compatibility_date: 2026-07-06 (Workers Cache launch date)
wrangler: 4.107.0 (per-entrypoint cache support)
- Placement: not set (verified via API:
resources.script_runtime.placement not set, worker settings.placement = {})
usage_model: standard
- Single Worker,
cloudflare_module-style default export.
Configuration (verified deployed via API)
resources.script_runtime:
cache_options.enabled: true
exports.default.cache.enabled: false
exports.Backend.cache.enabled: true
Wrangler config:
This is line-for-line the canonical gateway pattern from
https://developers.cloudflare.com/workers/cache/examples/#cache-authenticated-responses
Minimal reproduction
import { WorkerEntrypoint } from 'cloudflare:workers';
// Cached entrypoint (exports.Backend.cache.enabled = true)
export class Backend extends WorkerEntrypoint {
async fetch(request: Request): Promise<Response> {
console.log('[BACKEND-RAN]', new URL(request.url).pathname);
const body = JSON.stringify({ generatedAt: Date.now() });
return new Response(body, {
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'public, max-age=604800', // plain, no SWR/private/no-store
'Cache-Tag': 'backend:demo',
},
});
}
}
// Default entrypoint (exports.default.cache.enabled = false)
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
// Diagnostic route: prove routing + inspect cache status on two loopback
// calls to the SAME url, from the top-level frame.
if (url.pathname === '/probe') {
const target = 'https://example.com/data/' + Math.floor(Math.random() * 1e6);
const r1 = await ctx.exports.Backend.fetch(new Request(target));
await new Promise((res) => setTimeout(res, 1500));
const r2 = await ctx.exports.Backend.fetch(new Request(target));
return new Response(
JSON.stringify(
{
target,
req1_cfcache: r1.headers.get('cf-cache-status'),
req2_cfcache: r2.headers.get('cf-cache-status'),
req2_cachetag: r2.headers.get('cache-tag'),
},
null,
2,
),
{ headers: { 'content-type': 'application/json' } },
);
}
// Clean GET, no Authorization — no bypass trigger.
const clean = new URL(url);
clean.search = '';
return ctx.exports.Backend.fetch(new Request(clean, { method: 'GET' }));
},
};
Results
Routing is correct — calling ctx.exports.Backend.fetch(<bogus path>) runs Backend.fetch (not the default handler), and RPC methods on the same entrypoint resolve correctly. So this is not the #6215 misrouting.
Cache never engages — /probe output (two loopback calls to the same URL, 1.5s apart, top-level frame):
{
"req1_cfcache": null,
"req2_cfcache": null,
"req2_cachetag": "backend:demo"
}
Cf-Cache-Status is absent on both, Cache-Tag is never stripped, and [BACKEND-RAN] logs on every request (N runs for N requests) — including consecutive requests to the same URL within a single top-level invocation.
Isolation summary
| Variable |
State |
Result |
Config (cache_options, per-entrypoint exports) |
verified correct via API |
cache still absent |
compatibility_date |
2026-07-06 |
cache still absent |
| Smart Placement |
off (not set) |
cache still absent (so not #6215) |
| Request shape |
clean GET, no Authorization, query stripped |
cache still absent |
Cache-Control |
plain public, max-age=604800 |
cache still absent |
Routing (ctx.exports.Backend.fetch) |
reaches Backend.fetch |
correct |
| RPC on same entrypoint |
resolves correctly |
correct |
Cf-Cache-Status on loopback response |
never present |
— |
Cache-Tag on loopback response |
never stripped |
— |
Expected vs actual
- Expected: the second loopback call to the same URL returns
Cf-Cache-Status: HIT and Backend.fetch does not run (per docs: "loopback fetch() calls between entrypoints via ctx.exports" go through the cache).
- Actual: no
Cf-Cache-Status, Cache-Tag never stripped, Backend.fetch runs every request.
Question
Is per-entrypoint Workers Cache expected to be fully functional for ctx.exports loopbacks on all accounts as of the 2026-07-06 launch, or is there a rollout/account gate? Given routing is correct and placement is off, what would prevent the cache layer from sitting in front of a cache.enabled: true entrypoint?
Per-entrypoint Workers Cache does not intercept
ctx.exports.<Entrypoint>.fetch()loopbacks (routing correct, placement off, config verified)Summary
With the new per-entrypoint Workers Cache (launched 2026-07-06), a cached named
WorkerEntrypointinvoked viactx.exports.<Name>.fetch()from the default entrypoint is routed correctly but the cache layer never engages. The callee runs on every request,Cf-Cache-Statusis never set on the loopback response, andCache-Tagis never stripped — the platform's own signal that the response never transited the cache.This appears distinct from #6215: in my case the fetch is not misrouted (it reaches the correct entrypoint), and Smart Placement is disabled. The cache simply is not sitting in front of the entrypoint.
Environment
compatibility_date:2026-07-06(Workers Cache launch date)wrangler:4.107.0(per-entrypoint cache support)resources.script_runtime.placementnot set, workersettings.placement={})usage_model:standardcloudflare_module-style default export.Configuration (verified deployed via API)
resources.script_runtime:cache_options.enabled: trueexports.default.cache.enabled: falseexports.Backend.cache.enabled: trueWrangler config:
{ "compatibility_date": "2026-07-06", "cache": { "enabled": true }, "exports": { "default": { "type": "worker", "cache": { "enabled": false } }, "Backend": { "type": "worker", "cache": { "enabled": true } } } }This is line-for-line the canonical gateway pattern from
https://developers.cloudflare.com/workers/cache/examples/#cache-authenticated-responses
Minimal reproduction
Results
Routing is correct — calling
ctx.exports.Backend.fetch(<bogus path>)runsBackend.fetch(not the default handler), and RPC methods on the same entrypoint resolve correctly. So this is not the #6215 misrouting.Cache never engages —
/probeoutput (two loopback calls to the same URL, 1.5s apart, top-level frame):{ "req1_cfcache": null, "req2_cfcache": null, "req2_cachetag": "backend:demo" }Cf-Cache-Statusis absent on both,Cache-Tagis never stripped, and[BACKEND-RAN]logs on every request (N runs for N requests) — including consecutive requests to the same URL within a single top-level invocation.Isolation summary
cache_options, per-entrypointexports)compatibility_date2026-07-06GET, noAuthorization, query strippedCache-Controlpublic, max-age=604800ctx.exports.Backend.fetch)Backend.fetchCf-Cache-Statuson loopback responseCache-Tagon loopback responseExpected vs actual
Cf-Cache-Status: HITandBackend.fetchdoes not run (per docs: "loopback fetch() calls between entrypoints via ctx.exports" go through the cache).Cf-Cache-Status,Cache-Tagnever stripped,Backend.fetchruns every request.Question
Is per-entrypoint Workers Cache expected to be fully functional for
ctx.exportsloopbacks on all accounts as of the 2026-07-06 launch, or is there a rollout/account gate? Given routing is correct and placement is off, what would prevent the cache layer from sitting in front of acache.enabled: trueentrypoint?