TryGhost/Ghost · error · Error

Failed to update email preferences

Error message

Failed to update email preferences

What it means

Thrown in api.member.updateEmailPreferences (apps/portal/src/utils/api.js:467) when PUT to /members/api/member/newsletters/ (uuid/key auth) returns non-ok. Message 'Failed to update email preferences'. Used by the unsubscribe/manage-preferences flow when the member is not signed in but has a uuid+key token.

Source

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

                body.enable_comment_notifications = enableCommentNotifications;
            }

            if (enableUpdatesAndAnnouncements !== undefined) {
                body.enable_updates_and_announcements = enableUpdatesAndAnnouncements;
            }

            return makeRequest({
                url,
                method: 'PUT',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(body)
            }).then(function (res) {
                if (res.ok) {
                    return res.json();
                } else {
                    throw new Error('Failed to update email preferences');
                }
            });
        },

        async updateEmailAddress({email}) {
            const identity = await api.member.identity();
            const url = endpointFor({type: 'members', resource: 'member/email'});
            const body = {
                email,
                identity
            };

            return makeRequest({
                url,
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },

View on GitHub (pinned to 47d8b0e2ad)

Solutions

  1. Verify the uuid and key in the URL are intact and unused (request a fresh magic link if expired).
  2. Inspect the PUT response status/body — 404 = member gone, 401 = bad token, 422 = body invalid.
  3. Confirm at least one enabled newsletter exists (Settings > Newsletter).
  4. Re-prompt the user to sign in to manage preferences instead of relying on the token.

Example fix

// before
if (res.ok) { return res.json(); } else { throw new Error('Failed to update email preferences'); }

// after
if (res.ok) { return res.json(); }
if (res.status === 401 || res.status === 404) { throw new Error('Your preferences link has expired — request a new one'); }
throw new Error(`Failed to update email preferences (${res.status})`);
Defensive patterns

Strategy: validation

Validate before calling

// validate the token pair before calling
function isValidManagePrefsToken({uuid, key}) {
    return typeof uuid === 'string' && typeof key === 'string' && uuid.length > 0 && key.length > 0;
}

Try / catch

try {
    const updated = await api.member.updateEmailPreferences({uuid, key, newsletters});
    return updated;
} catch (err) {
    if (/expired/.test(err.message)) { promptSignIn(); }
    else { notifyError('Could not update preferences — please try again'); }
}

Prevention

When it happens

Trigger: Visitor opens a manage-preferences link with uuid+key; Portal PUTs the updated newsletters list; the response is 4xx/5xx — token expired/used, member not found, no newsletters configured, or the body shape is invalid.

Common situations: The uuid/key token was already rotated or expired; member was deleted; the link was opened after the token TTL elapsed; CSRF/identity check failed; Portal bundle / server version mismatch on the newsletters endpoint contract.

Related errors


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