GitbookIO/gitbook · error · Error

Failed to fetch search index: ${response.status}

Error message

Failed to fetch search index: ${response.status}

What it means

Thrown by fetchSiteIndexText in the GitBook search client when the HTTP request for the site's prebuilt search index returns a non-OK status. The function fetches indexURL, checks response.ok, and throws with the failing status code; the promise is memoized in siteIndexText and reset to null on failure so a later call retries the fetch.

Source

Thrown at packages/gitbook/src/components/Search/site-index.ts:68

    indexURL: string
): Promise<{ version: 1; pages: SiteIndexPage[] }> {
    return JSON.parse(await fetchSiteIndexText(indexURL));
}

/**
 * Drop the cached raw text (several MB for large sites) once a consumer has
 * turned it into a longer-lived form. Purely a memory release: a later consumer
 * re-fetches, hitting the HTTP cache.
 */
export function releaseSiteIndex(): void {
    siteIndexText = null;
}

function fetchSiteIndexText(indexURL: string): Promise<string> {
    if (!siteIndexText) {
        siteIndexText = fetch(indexURL).then((response) => {
            if (!response.ok) {
                throw new Error(`Failed to fetch search index: ${response.status}`);
            }
            return response.text();
        });

        siteIndexText.catch(() => {
            siteIndexText = null;
        });
    }

    return siteIndexText;
}

View on GitHub (pinned to db67585ee2)

Solutions

  1. Open the indexURL directly in a browser/curl to see the actual status and body (often 404 vs 403 tells the story).
  2. If 404: verify the site publishes a search index and that the URL/version segment is correct and current.
  3. If 401/403: ensure the request carries the visitor's auth cookies/headers for private sites.
  4. Rely on the built-in memoization reset: the failed promise is cleared, so calling fetchSiteIndex again after fixing the underlying issue retries rather than serving a rejected promise.

Example fix

// before
const index = await fetchSiteIndex(indexURL);

// after
const index = await fetchSiteIndex(indexURL).catch((error) => {
    if (String(error.message).startsWith('Failed to fetch search index:')) {
        return null; // fall back to non-index (slower) search or hide search UI
    }
    throw error;
});
Defensive patterns

Strategy: retry

Validate before calling

// Optional preflight (cheap HEAD) before the real fetch:
const ok = await fetch(indexURL, { method: 'HEAD' }).then((r) => r.ok).catch(() => false);
if (!ok) {
    fallbackToServerSearch();
}

Type guard

const isSearchIndexAvailable = async (url: string): Promise<boolean> => {
    try {
        const res = await fetch(url, { method: 'HEAD' });
        return res.ok;
    } catch {
        return false;
    }
};

Try / catch

try {
    const index = await fetchSiteIndex(indexURL);
} catch (error) {
    if (error instanceof Error && error.message.startsWith('Failed to fetch search index:')) {
        return fallbackSearch();
    }
    throw error;
}

Prevention

When it happens

Trigger: GET of the site index URL returning 404 (index not generated/deployed for the site), 401/403 (private site with bad auth), 500 (server error building the index), or any non-2xx; a CDN or middleware blocking the request; an incorrect indexURL passed to fetchSiteIndex/prefetchSiteIndex.

Common situations: Site deployed without a search index artifact (new sites, build config change); URL rewriting/proxying in local dev (the dev server proxy) mangling the index path; authentication/cookie issues on private spaces; host returning an HTML error page with status 404/500.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of GitbookIO/gitbook@db67585ee2 (2026-08-28). Data as JSON: /api/errors/7c0b07109560f6b6. Report an issue: GitHub.