{"record":{"id":"1671e8673234190e","repo":"TryGhost/Ghost","slug":"no-staff-invitation-email-found-for-email","errorCode":null,"errorMessage":"No staff invitation email found for ${email}","messagePattern":"No staff invitation email found for (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"e2e/helpers/playwright/fixture.ts","lineNumber":206,"sourceCode":"        context,\n        ghostAccountOwner: authenticatedSession.ghostAccountOwner\n    };\n}\n\nasync function getInvitationToken(emailClient: EmailClient, email: string): Promise<string> {\n    let messages;\n\n    try {\n        messages = await emailClient.search({subject: 'has invited you to join', to: email});\n    } catch (error) {\n        const detail = error instanceof Error ? `: ${error.message}` : '';\n        throw new Error(`No staff invitation email found for ${email}${detail}`);\n    }\n\n    const message = messages[0];\n\n    if (!message) {\n        throw new Error(`No staff invitation email found for ${email}`);\n    }\n\n    const detailedMessage = await emailClient.getMessageDetailed(message);\n    const inviteUrl = new URL(extractInviteLink(detailedMessage));\n    const token = inviteUrl.pathname.split('/').filter(Boolean).at(-1);\n\n    if (!token) {\n        throw new Error(`No invitation token found in URL for ${email}`);\n    }\n\n    return token;\n}\n\nasync function createStaffAccount(page: Page, emailClient: EmailClient, role: AssignableStaffRoleName): Promise<StaffAccount> {\n    const staffAccountFactory = createStaffAccountFactory(\n        page.request,\n        email => getInvitationToken(emailClient, email)\n    );","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/TryGhost/Ghost/blob/47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe/e2e/helpers/playwright/fixture.ts#L188-L224","documentation":"The search succeeded but returned an empty array: messages[0] is undefined, so no invitation email matched the subject/to filter. This means the invite was never sent, never delivered, or arrived but didn't match the search criteria. Distinct from 113 (search threw) — here the mailbox query worked but found nothing.","triggerScenarios":"Staff invite API call never actually sent the email. Email delivered to a different address than queried. Subject line changed in a Ghost version so the 'has invited you to join' filter misses. Mail delivery lag — the test queried before the message arrived.","commonSituations":"Mail delivery latency in CI; invitation API silently failed; wrong email address fixture; subject template changed in a Ghost release; mail server indexing delay.","solutions":["Poll the mailbox with a timeout instead of a single query — invitations often arrive with a few seconds lag.","Verify the staff invite API call returned success and used the same email being queried.","Confirm the subject filter still matches the current Ghost invitation template; update if it changed.","Check the mail backend actually received the message (search by recipient, not just subject)."],"exampleFix":"// before\nconst message = messages[0];\nif (!message) throw new Error(`No staff invitation email found for ${email}`);\n\n// after\nlet message;\nfor (let i = 0; i < 30 && !message; i++) {\n    messages = await emailClient.search({subject:'has invited you to join', to:email});\n    message = messages[0];\n    if (!message) await new Promise(r => setTimeout(r, 1000));\n}\nif (!message) throw new Error(`No staff invitation email found for ${email} after 30s`);","handlingStrategy":"retry","validationCode":"async function inviteArrived(c: EmailClient, email: string): Promise<boolean> {\n    const m = await c.search({subject:'has invited you to join', to:email});\n    return m.length > 0;\n}","typeGuard":null,"tryCatchPattern":"let message;\nfor (let i = 0; i < 30 && !message; i++) {\n    const m = await emailClient.search({subject:'has invited you to join', to:email});\n    message = m[0];\n    if (!message) await new Promise(r => setTimeout(r, 1000));\n}\nif (!message) throw new Error(`No staff invitation email found for ${email} after 30s`);","preventionTips":["Poll the mailbox with a timeout rather than querying once — delivery has lag.","Confirm the invite API call used the same email address.","Update the subject filter if Ghost's invitation template changes."],"tags":["e2e","email","invitations","polling","delivery-latency"],"backgroundTag":null,"analyzedSha":"47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe","analyzedAt":"2026-08-13T01:25:26.651Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}