GraphiteEditor/Graphite · error
Network request failed and no cache available for ${request.
Error message
Network request failed and no cache available for ${request.url} What it means
Thrown by the Graphite service worker's networkFirst strategy, which is used only for the font catalog API (https://api.graphite.art/font-list). It fires when the live fetch() rejects (offline, DNS failure, API unreachable) AND the runtime-fonts cache holds no previously stored response for that URL. The rejection propagates out of event.respondWith, so the page sees a failed request for the font list.
Source
Thrown at frontend/src/service-worker.js:46
const cache = await caches.open(cacheName);
const cached = await cache.match(request);
if (cached) return cached;
const response = await fetch(request);
if (isCacheable(response)) cache.put(request, response.clone());
return response;
}
async function networkFirst(request, cacheName) {
const cache = await caches.open(cacheName);
try {
const response = await fetch(request);
if (isCacheable(response)) cache.put(request, response.clone());
return response;
} catch {
const cached = await cache.match(request);
if (cached) return cached;
throw new Error(`Network request failed and no cache available for ${request.url}`);
}
}
// ================
// Lifecycle events
// ================
self.addEventListener("install", (event) => {
event.waitUntil(
(async () => {
// Precache app shell assets
const cache = await caches.open(STATIC_CACHE_NAME);
await Promise.all(
PRECACHE_MANIFEST.map(async (entry) => {
const response = await fetch(entry.url);
if (!response.ok) throw new Error(`Precache fetch failed for ${entry.url}: ${response.status}`);
// Strip the `redirected` flag which causes errors when served via respondWith
const cleaned = response.redirectedView on GitHub (pinned to c507b35645)
Solutions
- Bring the browser online and load the font list once so networkFirst caches a good response, then retest offline
- Catch the rejection in the fetch handler and return a 503 Response with an empty font list instead of letting it fail
- Verify the cache name passed to networkFirst (RUNTIME_FONTS) matches the cache the install-time prefetch writes to
- Check that a proxy, extension, or DNS issue is not blocking api.graphite.art
Example fix
// before (service-worker.js networkFirst)
} catch {
const cached = await cache.match(request);
if (cached) return cached;
throw new Error(`Network request failed and no cache available for ${request.url}`);
}
// after: degrade gracefully instead of throwing
} catch {
const cached = await cache.match(request);
if (cached) return cached;
return new Response("{\"fonts\":[]}", { status: 503, headers: { "Content-Type": "application/json" } });
} Defensive patterns
Strategy: fallback
Validate before calling
// Check whether the font catalog is cached before relying on it offline
async function fontListCached(): Promise<boolean> {
const cache = await caches.open("runtime-fonts");
return Boolean(await cache.match("https://api.graphite.art/font-list"));
} Try / catch
// In the SW fetch handler, catch the networkFirst rejection and degrade gracefully
event.respondWith(
networkFirst(request, RUNTIME_FONTS).catch(
() => new Response("{\"fonts\":[]}", { status: 503, headers: { "Content-Type": "application/json" } }),
),
); Prevention
- Keep the install-time font catalog prefetch healthy — it is the only thing that seeds the offline fallback
- Design the font picker UI to tolerate a failed or empty font list response
- Whenever adding a networkFirst route, pair it with a cached or synthetic fallback response
When it happens
Trigger: DevTools offline throttling or a genuinely offline machine combined with a font list that was never cached: the install-time prefetch of FONT_LIST_API is best-effort (wrapped in try/catch, only cached when response.ok), so a failed first fetch leaves the runtime-fonts cache empty and every later offline request hits this throw.
Common situations: Testing the PWA offline right after a fresh install where the font catalog prefetch failed; api.graphite.art blocked by an extension, firewall, or corporate proxy; a first response that was 4xx/5xx (isCacheable() refuses to store non-ok, non-opaque responses, so no offline fallback ever gets seeded).
Related errors
- Precache fetch failed for ${entry.url}: ${response.status}
- Failed to fetch Wasm binary part (status ${failedResponse.st
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/95f8a39389452001.
Report an issue: GitHub.