schollz/croc · error · Error

Streaming download service did not start

Error message

Streaming download service did not start

What it means

After registering croc-download-sw.js and awaiting serviceWorker.ready, streamingWorker() tries controller ?? active ?? waiting ?? installing to obtain a worker handle; if all are null it throws. This means registration nominally succeeded but no worker instance ever materialized — the script failed to install, was terminated, or was blocked.

Source

Thrown at web/src/protocol/storage.ts:188

let downloadWorker: Promise<ServiceWorker> | undefined;

async function streamingWorker() {
  downloadWorker ??= (async () => {
    if (!("serviceWorker" in navigator) || typeof MessageChannel === "undefined") {
      throw new Error("Streaming browser downloads are unavailable");
    }
    const registration = await navigator.serviceWorker.register(
      `${import.meta.env.BASE_URL}croc-download-sw.js`,
      { scope: import.meta.env.BASE_URL },
    );
    await navigator.serviceWorker.ready;
    const worker =
      navigator.serviceWorker.controller ??
      registration.active ??
      registration.waiting ??
      registration.installing;
    if (!worker) throw new Error("Streaming download service did not start");
    return worker;
  })();
  return downloadWorker;
}

class StreamingDownloadSink implements ReceiveSink {
  private offset = 0;
  private closed = false;
  private digest?: Uint8Array;
  private pending?: {
    resolve(): void;
    reject(error: Error): void;
  };

  private constructor(
    private port: MessagePort,
    private hashHandle: number,
  ) {

View on GitHub (pinned to e25f1bdc04)

Solutions

  1. Verify croc-download-sw.js is deployed at BASE_URL and served with Content-Type text/javascript — open the URL directly in the browser and check for a 200.
  2. Ensure the SW registration scope (BASE_URL) actually covers the page URL; with sub-path hosting, set BASE_URL correctly at build time.
  3. Re-check after a hard reload; a previously-failed install can leave registration in a bad state — unregister via navigator.serviceWorker.getRegistrations() then reload.
  4. Check the browser console for the service worker's own install/evaluate error and fix that first.

Example fix

# before: SW served at /assets/croc-download-sw.js but BASE_URL=/app/
# after: emit/copy the worker to /app/croc-download-sw.js (matches BASE_URL scope)
Defensive patterns

Strategy: retry

Validate before calling

async function downloadWorkerHealthy(): Promise<boolean> {
  if (!("serviceWorker" in navigator)) return false;
  try {
    const reg = await navigator.serviceWorker.getRegistration(
      `${import.meta.env.BASE_URL}croc-download-sw.js`,
    );
    return Boolean(reg?.active || reg?.installing || reg?.waiting);
  } catch {
    return false;
  }
}

Try / catch

try {
  const worker = await streamingWorker();
} catch (error) {
  if (error instanceof Error && error.message === "Streaming download service did not start") {
    downloadWorker = undefined; // clear the memoized failed promise
    for (const reg of await navigator.serviceWorker.getRegistrations()) await reg.unregister();
    location.reload(); // one clean retry after unregister; then surface the error
    return;
  }
  throw error;
}

Prevention

When it happens

Trigger: The service worker script fails to load/evaluate (404 on croc-download-sw.js at BASE_URL, syntax error, wrong MIME type), install is rejected (e.g. an install-event failure), a scope mismatch leaves no worker for the page's scope, or the browser blocks the worker (certain privacy modes, extensions, enterprise policy).

Common situations: Build/asset pipeline not emitting croc-download-sw.js or placing it outside import.meta.env.BASE_URL (common with sub-path deployments); dev server missing the file or serving it with an HTML 404 fallback; strict MIME checks rejecting the script; private-browsing modes where registration resolves but no worker activates.

Related errors


AI-assisted analysis of schollz/croc@e25f1bdc04 (2026-08-15). Data as JSON: /api/errors/6c858ccb4d252e83. Report an issue: GitHub.