angular/angular · error · SwCriticalError
Failed to update the caches for request to '${req.url}' (fet
Error message
Failed to update the caches for request to '${req.url}' (fetchAndCacheOnce): ${errorToString(err)} What it means
After a successful fetch, the service worker writes the response into CacheStorage and its metadata into IndexedDB; if that write throws — the code comment cites 'Entry was not found' when the user cleared all data via DevTools while the SW was still running and serving another tab — the SW can no longer work correctly and throws SwCriticalError (the situation is unrecoverable for that SW instance). The Driver falls back to a safe network fetch for the current request.
Source
Thrown at packages/service-worker/worker/src/assets.ts:353
const cache = await this.cache;
await cache.put(req, res.clone());
// If the request is not hashed, update its metadata, especially the timestamp. This is
// needed for future determination of whether this cached response is stale or not.
if (!this.hashes.has(this.adapter.normalizeUrl(req.url))) {
// Metadata is tracked for requests that are unhashed.
const meta: UrlMetadata = {ts: this.adapter.time, used};
const metaTable = await this.metadata;
await metaTable.write(req.url, meta);
}
return res;
} catch (err) {
// Among other cases, this can happen when the user clears all data through the DevTools,
// but the SW is still running and serving another tab. In that case, trying to write to the
// caches throws an `Entry was not found` error.
// If this happens the SW can no longer work correctly. This situation is unrecoverable.
throw new SwCriticalError(
`Failed to update the caches for request to '${
req.url
}' (fetchAndCacheOnce): ${errorToString(err)}`,
);
}
} finally {
// Finally, it can be removed from `inFlightRequests`. This might result in a double-remove
// if some other chain was already making this request too, but that won't hurt anything.
this.inFlightRequests.delete(req.url);
}
}
protected async fetchFromNetwork(req: Request, redirectLimit: number = 3): Promise<Response> {
// Make a cache-busted request for the resource.
const res = await this.cacheBustedFetchFromNetwork(req);
// Check for redirected responses, and follow the redirects.
if ((res as any)['redirected'] && !!res.url) {View on GitHub (pinned to 51cb07e980)
Solutions
- Unregister the service worker and reload to force a clean install: navigator.serviceWorker.getRegistrations().then(rs => rs.forEach(r => r.unregister())).
- When clearing storage intentionally, close all app tabs first so no SW survives to observe the wipe.
- Ship a new app version so existing clients pick up a fresh SW with rebuilt caches.
Defensive patterns
Strategy: fallback
Prevention
- When clearing site data intentionally, close all tabs of the app first so no service worker survives the wipe.
- Provide an in-app recovery path (unregister SW + reload) for users who report offline breakage after clearing data.
- Ship new app versions periodically so stale/broken SW instances get replaced.
When it happens
Trigger: cache.put() or the metadata-table write rejecting inside fetchAndCacheOnce: site data cleared while the SW stays alive in another tab, storage eviction under quota pressure, or browser storage corruption.
Common situations: 'Clear site data' clicked in DevTools with the PWA open in another window/tab; iOS/Safari aggressive storage eviction; low-disk devices where the browser revokes storage.
Related errors
- Cache is throwing while looking for a match: ${error}
- Not a valid duration: ${match}
- Not a valid duration unit: ${res[2]}
- Asset-group '${group.name}' in 'ngsw-config.json' uses the '
- SERVICE_WORKER_DISABLED_OR_NOT_SUPPORTED_BY_THIS_BROWSER
AI-assisted analysis of angular/angular@51cb07e980 (2026-08-22).
Data as JSON: /api/errors/928857924d0d4609.
Report an issue: GitHub.