{"record":{"id":"d55536b475f7796e","repo":"TryGhost/Ghost","slug":"failed-to-signout","errorCode":null,"errorMessage":"Failed to signout","messagePattern":"Failed to signout","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"apps/portal/src/utils/api.js","lineNumber":422,"sourceCode":"        },\n\n        signout(all = false) {\n            const url = endpointFor({type: 'members', resource: 'session'});\n            return makeRequest({\n                url,\n                method: 'DELETE',\n                headers: {\n                    'Content-Type': 'application/json'\n                },\n                body: JSON.stringify({\n                    all\n                })\n            }).then(function (res) {\n                if (res.ok) {\n                    window.location.replace(siteUrl);\n                    return 'Success';\n                } else {\n                    throw new Error('Failed to signout');\n                }\n            });\n        },\n\n        async newsletters({uuid, key}) {\n            let url = endpointFor({type: 'members', resource: `member/newsletters`});\n            url = url + `?uuid=${uuid}&key=${key}`;\n            return makeRequest({\n                url,\n                credentials: 'same-origin'\n            }).then(function (res) {\n                if (!res.ok || res.status === 204) {\n                    return null;\n                }\n                return res.json();\n            });\n        },\n","sourceCodeStart":404,"sourceCodeEnd":440,"githubUrl":"https://github.com/TryGhost/Ghost/blob/47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe/apps/portal/src/utils/api.js#L404-L440","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Reload the page — if the session is already gone, Portal should treat the member as signed out anyway.","Confirm third-party cookie blocking is not stripping the session cookie (especially in Safari/ITP).","Check that the page origin matches siteUrl so the cookie scope covers the request.","If the issue persists, clear site cookies and sign in again."],"exampleFix":"// before\nif (res.ok) { window.location.replace(siteUrl); return 'Success'; } else { throw new Error('Failed to signout'); }\n\n// after: still redirect on session-already-gone (401)\nif (res.ok || res.status === 401) { window.location.replace(siteUrl); return 'Success'; }\nthrow new Error(`Failed to signout (${res.status})`);","handlingStrategy":"fallback","validationCode":"// if the session cookie is missing, skip the call and just redirect\nfunction hasSessionCookie() {\n    return document.cookie.split('; ').some(c => c.startsWith('ghost-members-session'));\n}","typeGuard":null,"tryCatchPattern":"try {\n    await api.member.signout(all);\n} catch (err) {\n    // err.message === 'Failed to signout'\n    // session is probably already gone — redirect anyway\n    window.location.replace(siteUrl);\n}","preventionTips":["Treat 401/404 sign-out responses as success and still redirect.","Ensure cookie scope covers the page origin so DELETE is authenticated.","Disable edge caching for /members/api/session/.","Avoid double sign-out across tabs."],"tags":["portal","signout","session","members-api"],"backgroundTag":null,"analyzedSha":"47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe","analyzedAt":"2026-08-13T01:25:26.651Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}