TryGhost/Ghost · error · Error

Failed to fetch site data

Error message

Failed to fetch site data

What it means

Thrown in apps/portal/src/utils/api.js api.site.read() when GET {siteUrl}/members/api/site/ returns non-ok. This is the first call Portal makes on boot to load the site, member, and tiers. The generic message 'Failed to fetch site data' hides the underlying status.

Source

Thrown at apps/portal/src/utils/api.js:48

        };
        return fetch(url, options);
    }
    const api = {};

    api.site = {
        read() {
            const url = endpointFor({type: 'members', resource: 'site'});
            return makeRequest({
                url,
                method: 'GET',
                headers: {
                    'Content-Type': 'application/json'
                }
            }).then(function (res) {
                if (res.ok) {
                    return res.json();
                } else {
                    throw new Error('Failed to fetch site data');
                }
            });
        },

        newsletters() {
            const url = contentEndpointFor({resource: 'newsletters', params: {limit: 100}});
            return makeRequest({
                url,
                method: 'GET',
                headers: {
                    'Content-Type': 'application/json'
                }
            }).then(function (res) {
                if (res.ok) {
                    return res.json();
                } else {
                    throw new Error('Failed to fetch site data');
                }

View on GitHub (pinned to 47d8b0e2ad)

Solutions

  1. Open /members/api/site/ directly in a browser and inspect the HTTP status and body.
  2. Confirm siteUrl in the Ghost config matches the origin serving the page (check /ghost/api/config/).
  3. Verify the members/portal feature is enabled and the theme includes the Portal snippet.
  4. Clear any CDN/edge cache that may be serving a stale error response for the members API path.

Example fix

// before
if (res.ok) { return res.json(); } else { throw new Error('Failed to fetch site data'); }

// after: include status for diagnostics
if (res.ok) { return res.json(); }
throw new Error(`Failed to fetch site data (${res.status} ${res.statusText})`);
Defensive patterns

Strategy: retry

Validate before calling

// sanity-check the endpoint and origin before boot
function preflightSiteEndpoint(siteUrl) {
    const u = new URL(siteUrl);
    if (u.origin !== window.location.origin) {
        console.warn('siteUrl origin mismatch may cause CORS for /members/api/site/');
    }
}

Try / catch

try {
    const data = await api.site.read();
    return data;
} catch (err) {
    // err.message === 'Failed to fetch site data'
    showFatalError('Portal could not load — please refresh. If this persists, contact the site owner.');
    throw err;
}

Prevention

When it happens

Trigger: Portal initializes; makeRequest to /members/api/site/ returns 4xx/5xx — common causes: members API disabled, siteUrl mismatch, portal-Integration middleware returns 404, server error bootstrapping members service.

Common situations: Ghost server runs an older version that doesn't expose /members/api/site/; the page is served from a different origin than siteUrl (CORS / subdomain mismatch); members feature disabled in labs; reverse proxy returning a cached error page; site in maintenance mode.

Related errors


AI-assisted analysis of TryGhost/Ghost@47d8b0e2ad (2026-08-13). Data as JSON: /api/errors/6ef2d43b3e762f2a. Report an issue: GitHub.