{"record":{"id":"58942fdd63b31404","repo":"TryGhost/Ghost","slug":"timeout-after-timeoutms-ms-waiting-for-search-re","errorCode":null,"errorMessage":"Timeout after ${timeoutMs}ms waiting for search results","messagePattern":"Timeout after (.+?)ms waiting for search results","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"e2e/helpers/services/email/mail-pit.ts","lineNumber":136,"sourceCode":"        while (Date.now() - startTime < timeoutMs) {\n            const messages = await searchFn();\n\n            if (numberOfMessages === null) {\n                if (messages.length > 0) {\n                    debug(`Found ${messages.length} messages`);\n                    return messages;\n                }\n            } else {\n                if (messages.length === numberOfMessages) {\n                    debug(`Found ${messages.length} messages`);\n                    return messages;\n                }\n            }\n\n            await this.delay(500);\n        }\n\n        throw new Error(`Timeout after ${timeoutMs}ms waiting for search results`);\n    }\n\n    private async delay(milliseconds: number) {\n        await new Promise<void>((resolve) => {\n            setTimeout(resolve, milliseconds);\n        });\n    }\n\n    private async executeApiCall(endpoint: string, callType: string, method: string = 'GET'): Promise<Response> {\n        debug(`${callType} through ${endpoint}`);\n        const response = await fetch(`${this.apiUrl}/${endpoint}`, {method: method});\n        if (!response.ok) {\n            throw new Error(`Failed to ${callType}: ${response.statusText}`);\n        }\n\n        debug(`${callType} through ${endpoint} succeeded`);\n        return response;\n    }","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/TryGhost/Ghost/blob/47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe/e2e/helpers/services/email/mail-pit.ts#L118-L154","documentation":"Thrown by `MailPit.searchWithWait` when the polling loop exits the timeout window without matching messages. The loop polls Mailpit's search endpoint every 500ms until it finds any message (or exactly `numberOfMessages`); exhaustion means the expected email never arrived in the window.","triggerScenarios":"An email-dependent assertion waits for messages via `searchByRecipient`/`searchByQuery` with a timeout, and the condition (`messages.length > 0` or `=== numberOfMessages`) is never satisfied before `timeoutMs` elapses.","commonSituations":"Mailpit is slow to index; Ghost did not send the email; the recipient/search query does not match the sent mail; `numberOfMessages` expectation is wrong (too many/few); network latency between test runner and Mailpit.","solutions":["Increase `timeoutMs` for the search call in slow environments.","Verify the search query parameters match how the email was actually sent (recipient address, subject).","Confirm Ghost dispatched the email and Mailpit received it (check Mailpit UI/logs).","Correct the expected `numberOfMessages` if the test assumption about email count is wrong."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use a generous `timeoutMs` for email searches in slow environments.","Match search query parameters exactly to how the email was addressed.","Confirm Mailpit received the email (UI/logs) before assuming Ghost failed to send."],"tags":["email","e2e","mailpit","polling","timeout"],"backgroundTag":null,"analyzedSha":"47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe","analyzedAt":"2026-08-13T01:25:26.651Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}