JavaScript Cache API Not Storing Response Fix
In this tutorial, you'll learn about JavaScript Cache API Not Storing Response Fix. We cover key concepts, practical examples, and best practices.
The Problem
The Cache API silently fails to store responses when the response body has already been consumed, when the response is an opaque response from a different origin, or when storage limits are exceeded. You fetch data but the cache stays empty.
Quick Fix
Step 1: Clone response before caching
// Wrong — response body consumed by json(), then cache gets empty body
const response = await fetch('/api/data');
const data = await response.json();
await caches.open('v1').then(cache => cache.put('/api/data', response));
// Right — clone the response
const response = await fetch('/api/data');
const cache = await caches.open('v1');
cache.put('/api/data', response.clone()); // clone before reading
const data = await response.json();
Step 2: Handle opaque responses
// Wrong — opaque responses (no-cors) have status 0 and empty body
const response = await fetch('https://other-origin.com/image.png', {
mode: 'no-cors'
});
const cache = await caches.open('v1');
cache.put('/external-image', response);
// Cache.put() fails silently for opaque responses
// Right — only cache same-origin or CORS responses
const response = await fetch('https://other-origin.com/image.png');
if (response.type === 'opaque') {
// Cannot reliably cache opaque responses
console.warn('Opaque response cannot be cached');
} else {
const cache = await caches.open('v1');
cache.put('/external-image', response);
}
Step 3: Check storage quota before caching
async function cacheWithQuotaCheck(url) {
const estimate = await navigator.storage.estimate();
const available = estimate.quota - estimate.usage;
const response = await fetch(url);
const cloned = response.clone();
const size = parseInt(cloned.headers.get('content-length') || '0');
// Wrong — ignores storage limits
// (await caches.open('v1')).put(url, cloned);
// Right — check quota first
if (size > available) {
console.warn('Not enough storage to cache:', url);
return response;
}
const cache = await caches.open('v1');
await cache.put(url, cloned);
return response;
}
Step 4: Use Cache API in service worker properly
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cached) => {
// Wrong — returns cached and fetches without updating cache
return cached || fetch(event.request);
// Right — cache then network strategy
const fetchPromise = fetch(event.request).then((response) => {
const clone = response.clone();
caches.open('v1').then(cache => cache.put(event.request, clone));
return response;
});
return cached || fetchPromise;
})
);
});
Prevention
- Always clone
Responseobjects before caching — you cannot reuse a consumed body - Check
response.type !== 'opaque'before caching cross-origin resources - Monitor storage usage with
navigator.storage.estimate() - Delete old caches during service worker activation to free space
- Use the Cache API only within secure contexts (HTTPS or localhost)
Common Mistakes with web api cache
- Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable
- Using
headandtailinstead of pattern matching, causing runtime errors on empty lists - Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
These mistakes appear frequently in real-world JS code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro