koala73/worldmonitor · error
Service worker unavailable.
Error message
Service worker unavailable.
What it means
Thrown by subscribeToPush() in src/services/push-notifications.ts when getRegistration() returns null: navigator.serviceWorker.ready threw (or the context was unsupported), meaning no active service worker registration could be obtained. Push subscriptions must be created from a service worker registration, so subscription cannot proceed. The VitePWA worker registers at '/'; if it never registers, is blocked, or its registration is corrupt/unregistered, this error results.
Source
Thrown at src/services/push-notifications.ts:133
'Content-Type': 'application/json',
...(init.headers ?? {}),
Authorization: `Bearer ${token}`,
},
});
}
/**
* Ask permission (if needed), subscribe via pushManager, and register
* the endpoint with the server. Resolves with the payload the server
* accepted, or throws on cancel / denial / network failure.
*/
export async function subscribeToPush(expectedUserId?: string): Promise<SubscriptionPayload> {
assertExpectedAccount(expectedUserId);
if (!isWebPushSupported()) {
throw new Error('Web push is not supported in this browser.');
}
const reg = await getRegistration();
if (!reg) throw new Error('Service worker unavailable.');
const perm = await Notification.requestPermission();
if (perm !== 'granted') {
throw new Error(
perm === 'denied'
? 'Notifications are blocked. Enable them in your browser settings to continue.'
: 'Notifications permission was not granted.',
);
}
// Re-use an existing subscription if pushManager already has one
// for this origin. Re-registering via POST keeps server state in
// sync even when the browser has a stale subscription — this is
// important after sign-out/sign-in, where the browser's push
// identity persists but the Convex row does not.
let sub = await reg.pushManager.getSubscription();
if (!sub) {
sub = await reg.pushManager.subscribe({View on GitHub (pinned to eeab0a219f)
Solutions
- Reload the page and check DevTools → Application → Service Workers: a worker should be 'activated and running' for this origin.
- If none registers, fix the VitePWA/hosting setup so the worker script is served at '/' and re-register (navigator.serviceWorker.register('/sw.js')).
- Clear site data (workers + caches) and reload to recover from a corrupt registration.
- On managed/locked-down browsers, surface an informational 'notifications unavailable' message rather than retrying.
Example fix
// before
await subscribeToPush(userId);
// after
if (!('serviceWorker' in navigator)) { return; }
await navigator.serviceWorker.register('/sw.js').catch(() => null);
const reg = await navigator.serviceWorker.ready;
if (!reg) {
showNotice('Notifications are unavailable because the service worker could not load. Reload and try again.');
return;
}
await subscribeToPush(userId); Defensive patterns
Strategy: validation
Validate before calling
if (!('serviceWorker' in navigator)) return;
await navigator.serviceWorker.register('/sw.js').catch(() => null);
let reg: ServiceWorkerRegistration | undefined;
try {
reg = await navigator.serviceWorker.ready;
} catch { reg = undefined; }
if (!reg) {
showNotice('Notifications are unavailable: the service worker could not load. Reload and try again.');
return;
}
await subscribeToPush(expectedUserId); Type guard
async function hasActiveServiceWorker(): Promise<boolean> {
if (!('serviceWorker' in navigator)) return false;
try { return !!(await navigator.serviceWorker.getRegistration()); } catch { return false; }
} Try / catch
try {
await subscribeToPush(expectedUserId);
} catch (err) {
if (err instanceof Error && err.message === 'Service worker unavailable.') {
promptReloadWithRecoveryHint(); // re-registration or cache clear usually fixes it
return;
}
throw err;
} Prevention
- Verify the VitePWA worker is registered (Application → Service Workers) before enabling push UI.
- Ensure hosting serves the worker script at '/' correctly in every environment.
- Offer a 'clear site data and reload' recovery action when the registration is corrupt.
When it happens
Trigger: Browser privacy modes or policies that block service workers; the service worker was unregistered (e.g., devtools 'Unregister' or a failed update left no active worker); serving the app from a context where the SW script 404s (misconfigured static hosting of sw.js); security software stripping the worker script.
Common situations: Dev servers without the PWA plugin active so no worker is ever registered; hosting misroutes for /sw.js or /service-worker.js; enterprise-managed browsers with SW disabled; corrupted registrations after version churn.
Related errors
- DNS ${recordType} lookup failed: HTTP ${response.status}
- DNS ${recordType} lookup failed: status ${data.Status}
- callbackUrl DNS resolution failed: ${message}
- callbackUrl DNS resolution returned no addresses
- Authenticated account changed during push setup
AI-assisted analysis of koala73/worldmonitor@eeab0a219f (2026-08-21).
Data as JSON: /api/errors/9654f880ff433f22.
Report an issue: GitHub.