TL;DR: caches.default only gets full edge backing on a zone route (your own domain on the account). On workers.dev or in some local contexts it is limited or absent, so cache.put can fail. Use a named cache from caches.open for behavior that works everywhere, and check that your put meets the cacheability rules.

```text
workerd: cache API put failed, cache unavailable in workerd
```

1. Identify where the worker runs. Check your routes: is the worker attached to a custom domain route on your account, or only on a workers.dev subdomain?
   Expected: you know which context the failing code runs in.

2. Check the put preconditions in your code. The request being cached must be a GET, and the response must be cacheable (a cacheable status, no conflicting directives that forbid storing it).
   Expected: you can point at the request method and response headers and confirm they allow caching.

3. Switch the failing path to a named cache, which is available in every context:
   ```js
   const cache = await caches.open("my-app-cache");
   await cache.put(request, response);
   ```
   Expected: the put succeeds in local dev, on workers.dev, and on the custom domain.

4. If you specifically need caches.default edge behavior, move that code path behind a zone route on your own domain and retest.
   Expected: cache.put against caches.default succeeds when the request flows through the zone.

5. In local dev, rerun with `wrangler dev` and confirm the same code path caches and serves hits.
   Expected: repeated requests hit the cached response instead of recomputing it.

## Use this when
- cache.put throws or silently does nothing in one environment but not another
- caches.default works on your custom domain but fails on workers.dev or in local dev
- you are caching API responses or HTML inside a worker and need consistent behavior
- the failure appeared after moving the worker from a zone route to workers.dev

## Not for this skill when
- you are trying to purge or inspect the Cloudflare CDN cache from the dashboard (different feature)
- the problem is stale content being served (that is TTL and revalidation, not put failing)
- cache.match returns misses because the cache key differs per request (key normalization issue)
- you need cross-worker shared caching with strong consistency (look at KV or D1 instead)

## Variant phrasings
- caches.default not available in worker
- Cloudflare Worker cache.put throws
- cache API unavailable in workerd local dev
- workers.dev cache.put fails but custom domain works
- Cache API put rejected in Cloudflare Worker

## Why it happens
caches.default is tied to the edge cache of a zone, so it only has full backing when the worker handles requests on a domain in your account. Outside that context the default cache is limited or unavailable, and puts fail. A named cache from caches.open is a separate storage namespace that workerd provides in every context, which is why switching to one fixes the inconsistency.

## Edge cases
- Responses with Set-Cookie or certain auth headers are not stored. Strip or vary on them deliberately.
- Only GET requests are cached. A POST to the same URL will never hit the cache.
- Large objects can be rejected. Keep cached bodies within the documented object size limits or store big blobs in R2 and cache a pointer.
- In local dev the cache does not persist across restarts unless you pass the persist flag, so a "cold" local cache after every restart is normal.
- Cache keys include the full URL. Query-string ordering differences cause misses that look like put failures.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_AMwwzSZ6nBabHxjyfbD28Q
