TryGhost/Ghost · warning · Error

Failed to signout

Error message

Failed to signout

What it means

Thrown in api.member.signout() (apps/portal/src/utils/api.js:422) when DELETE /members/api/session/ returns non-ok. Message 'Failed to signout'. On success it does window.location.replace(siteUrl); on failure it throws without redirecting.

Source

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

        },

        signout(all = false) {
            const url = endpointFor({type: 'members', resource: 'session'});
            return makeRequest({
                url,
                method: 'DELETE',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    all
                })
            }).then(function (res) {
                if (res.ok) {
                    window.location.replace(siteUrl);
                    return 'Success';
                } else {
                    throw new Error('Failed to signout');
                }
            });
        },

        async newsletters({uuid, key}) {
            let url = endpointFor({type: 'members', resource: `member/newsletters`});
            url = url + `?uuid=${uuid}&key=${key}`;
            return makeRequest({
                url,
                credentials: 'same-origin'
            }).then(function (res) {
                if (!res.ok || res.status === 204) {
                    return null;
                }
                return res.json();
            });
        },

View on GitHub (pinned to 47d8b0e2ad)

Solutions

  1. Reload the page — if the session is already gone, Portal should treat the member as signed out anyway.
  2. Confirm third-party cookie blocking is not stripping the session cookie (especially in Safari/ITP).
  3. Check that the page origin matches siteUrl so the cookie scope covers the request.
  4. If the issue persists, clear site cookies and sign in again.

Example fix

// before
if (res.ok) { window.location.replace(siteUrl); return 'Success'; } else { throw new Error('Failed to signout'); }

// after: still redirect on session-already-gone (401)
if (res.ok || res.status === 401) { window.location.replace(siteUrl); return 'Success'; }
throw new Error(`Failed to signout (${res.status})`);
Defensive patterns

Strategy: fallback

Validate before calling

// if the session cookie is missing, skip the call and just redirect
function hasSessionCookie() {
    return document.cookie.split('; ').some(c => c.startsWith('ghost-members-session'));
}

Try / catch

try {
    await api.member.signout(all);
} catch (err) {
    // err.message === 'Failed to signout'
    // session is probably already gone — redirect anyway
    window.location.replace(siteUrl);
}

Prevention

When it happens

Trigger: Member clicks sign out; Portal DELETEs the session; the response is 4xx/5xx — typically the session cookie already expired, the CSRF token is missing, or the server cannot reach the session store.

Common situations: Session already invalid server-side; cookies blocked/cleared by the browser so the request lacks credentials; reverse proxy stripping cookies; cluster session store out of sync; user clicked sign-out in two tabs simultaneously.

Related errors


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