{"record":{"id":"763342e494e2a2a2","repo":"TryGhost/Ghost","slug":"failed-to-update-member-763342","errorCode":null,"errorMessage":"Failed to update member","messagePattern":"Failed to update member","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/portal/src/actions.js","lineNumber":670,"sourceCode":"        } catch (err) {\n            return {\n                success: false,\n                error: err\n            };\n        }\n    }\n    return null;\n}\n\nasync function updateMemberData({data, state, api}) {\n    const name = data?.name?.trim();\n    const originalName = getMemberName({member: state.member});\n\n    if (originalName !== name) {\n        try {\n            const member = await api.member.update({name});\n            if (!member) {\n                throw new Error('Failed to update member');\n            }\n            return {\n                member,\n                success: true\n            };\n        } catch (err) {\n            return {\n                success: false,\n                error: err\n            };\n        }\n    }\n    return null;\n}\n\nasync function refreshMemberData({state, api}) {\n    if (state.member) {\n        try {","sourceCodeStart":652,"sourceCodeEnd":688,"githubUrl":"https://github.com/TryGhost/Ghost/blob/47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe/apps/portal/src/actions.js#L652-L688","documentation":"Thrown in apps/portal/src/actions.js updateMemberData when a name change is requested but api.member.update({name}) resolves falsy. The action catches it and returns {success:false, error:err} so the UI shows a profile-update failure rather than crashing.","triggerScenarios":"Member edits their display name in Portal account page; originalName !== name so the update fires; api.member.update resolves but the returned member is null/undefined.","commonSituations":"Expired member session after long idle; backend rejecting the new name silently (e.g. server-side length limit); response-shape drift between Portal and Ghost server versions; network hiccup returning an empty 200.","solutions":["Verify the member session is valid — call api.member.identity() or reload; re-authenticate if expired.","Inspect the PUT /members/api/member/ response in Network tab; confirm a non-empty member object.","Trim and length-check the name client-side before sending (Ghost limits names server-side).","Align Portal bundle version with the Ghost server version."],"exampleFix":"// before\nconst member = await api.member.update({name});\nif (!member) {\n    throw new Error('Failed to update member');\n}\n\n// after: validate input then throw a more useful signal\nconst trimmed = name?.slice(0, 200);\nif (!trimmed) {\n    return {success: false, error: new Error('Name is empty')};\n}\nconst member = await api.member.update({name: trimmed});\nif (!member) {\n    throw new Error('Server returned no member — session may have expired');\n}","handlingStrategy":"validation","validationCode":"// validate + bound the name before sending\nfunction normalizeName(name) {\n    const trimmed = (name || '').trim();\n    if (!trimmed) { return null; } // nothing to change\n    if (trimmed.length > 200) { throw new Error('Name is too long (200 chars max)'); }\n    return trimmed;\n}","typeGuard":"function isMemberResponse(value) {\n    return value != null && typeof value === 'object' && typeof value.uuid === 'string';\n}","tryCatchPattern":"try {\n    const member = await api.member.update({name});\n    if (!member) { throw new Error('Server returned no member — session may have expired'); }\n    return {member, success: true};\n} catch (err) {\n    return {success: false, error: err};\n}","preventionTips":["Trim and length-check the name client-side before issuing the update.","Skip the API call entirely when originalName === name (Portal already does this).","Verify the member session is still valid before mutations.","Show a precise error (expired session vs. server rejection) to the user."],"tags":["portal","member-profile","members-api","validation"],"backgroundTag":null,"analyzedSha":"47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe","analyzedAt":"2026-08-13T01:25:26.651Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}